Creating new pipeline using seurat v4.0.2 available 2021.06.23
Important notes:

Setup

Load libraries required for Seuratv4

knitr::opts_knit$set(root.dir = "~/Desktop/10XGenomicsData/msAggr_scRNASeq/IndividualPops/")
library(dplyr)
library(Seurat)
library(patchwork)
library(ggplot2)
library(clustree)
Loading required package: ggraph

Source functions

source("~/Desktop/10XGenomicsData/msAggr_scRNASeq/RFunctions/read_10XGenomics_data.R")
source("~/Desktop/10XGenomicsData/msAggr_scRNASeq/RFunctions/PercentVariance.R")
source("~/Desktop/10XGenomicsData/msAggr_scRNASeq/RFunctions/ColorPalette.R")
source("~/Desktop/10XGenomicsData/msAggr_scRNASeq/RFunctions/Mouse2Human_idconversion.R")

A note about using SCTransform versus ScaleData

https://bioconductor.org/packages/3.10/workflows/vignettes/simpleSingleCell/inst/doc/batch.html#62_for_gene-based_analyses >You can also normalize and scale data for the RNA assay. There are numerous resources on this, but Aaron Lun describes why the original log-normalized values should be used for DE and visualizations of expression quite well here: > >For gene-based procedures like differential expression (DE) analyses or gene network construction, it is desirable to use the original log-expression values or counts. The corrected values are only used to obtain cell-level results such as clusters or trajectories. Batch effects are handled explicitly using blocking terms or via a meta-analysis across batches. We do not use the corrected values directly in gene-based analyses, for various reasons: > >It is usually inappropriate to perform DE analyses on batch-corrected values, due to the failure to model the uncertainty of the correction. This usually results in loss of type I error control, i.e., more false positives than expected. > >The correction does not preserve the mean-variance relationship. Applications of common DE methods like edgeR or limma are unlikely to be valid. > >Batch correction may (correctly) remove biological differences between batches in the course of mapping all cells onto a common coordinate system. Returning to the uncorrected expression values provides an opportunity for detecting such differences if they are of interest. Conversely, if the batch correction made a mistake, the use of the uncorrected expression values provides an important sanity check. > >In addition, the normalized values in SCT and integrated assays don’t necessary correspond to per-gene expression values anyway, rather containing residuals (in the case of the scale.data slot for each). ## Set global variables

projectName <- "LSKSubpop"
jackstraw.dim <- 40

Store session info

sessionInfo.filename <- paste0(projectName, "_sessionInfo.txt")
sink(sessionInfo.filename)
sessionInfo()
sink()
setwd("~/Desktop/10XGenomicsData/cellRanger/") # temporarily changing wd only works if you run the entire chunk at once
data_file.list <- read_10XGenomics_data(sample.list = c("LSKm2"))
data.object<-Read10X(data_file.list)
seurat.object<- CreateSeuratObject(counts = data.object, min.cells = 3, min.genes = 200, project = projectName)

Clean up to free memory

remove(data.object)

Add mitochondrial metadata and plot some basic features

seurat.object[["percent.mt"]] <- PercentageFeatureSet(seurat.object, pattern = "^mt-")
VlnPlot(seurat.object, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3, pt.size = 0, fill.by = 'orig.ident', )

plot1 <- FeatureScatter(seurat.object, feature1 = "nCount_RNA", feature2 = "percent.mt", group.by = "orig.ident", pt.size = 0.01)
plot2 <- FeatureScatter(seurat.object, feature1 = "nCount_RNA", feature2 = "nFeature_RNA", group.by = "orig.ident", pt.size = 0.01)
plot1 + plot2

remove low quality cells require: nFeature_RNA between 200 and 4000 (inclusive) require: percent.mt <= 5

print(paste("original object:", nrow(seurat.object@meta.data), "cells", sep = " "))
[1] "original object: 11187 cells"
seurat.object <- subset(seurat.object, 
                                                subset = nFeature_RNA >=200 & 
                                                    nFeature_RNA <= 4000 & 
                                                    percent.mt <= 5
)
print(paste("new object:", nrow(seurat.object@meta.data), "cells", sep = " "))
[1] "new object: 10627 cells"

Normalization

Struggling to wrap my head around this one. It seems that SCTransform is best for batch correction, but NormalizeData and ScaleData are best for DGE. Several vignettes have performed both

`selection.method
How to choose top variable features. Choose one of :

vst: First, fits a line to the relationship of log(variance) and log(mean) using local polynomial regression (loess). Then standardizes the feature values using the observed mean and expected variance (given by the fitted line). Feature variance is then calculated on the standardized values after clipping to a maximum (see clip.max parameter).

mean.var.plot (mvp): First, uses a function to calculate average expression (mean.function) and dispersion (dispersion.function) for each feature. Next, divides features into num.bin (deafult 20) bins based on their average expression, and calculates z-scores for dispersion within each bin. The purpose of this is to identify variable features while controlling for the strong relationship between variability and average expression.

dispersion (disp): selects the genes with the highest dispersion values`

seurat.object <- NormalizeData(seurat.object, normalization.method = "LogNormalize", scale.factor = 10000)
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|

Find variable features

seurat.object <- FindVariableFeatures(seurat.object, selection.method = "vst", nfeatures = 2000)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
top10 <- head(VariableFeatures(seurat.object), 10)
plot1 <- VariableFeaturePlot(seurat.object)
plot2 <- LabelPoints(plot = plot1, points = top10, repel = TRUE)
When using repel, set xnudge and ynudge to 0 for optimal results
plot1 + plot2

Scale data (linear transformation)

all.genes <- rownames(seurat.object)
seurat.object <- ScaleData(seurat.object, features = all.genes, vars.to.regress = c("nCount_RNA", "nFeature_RNA"))
Regressing out nCount_RNA, nFeature_RNA

  |                                                                                                                                                                                               
  |                                                                                                                                                                                         |   0%
  |                                                                                                                                                                                               
  |=                                                                                                                                                                                        |   0%
  |                                                                                                                                                                                               
  |=                                                                                                                                                                                        |   1%
  |                                                                                                                                                                                               
  |==                                                                                                                                                                                       |   1%
  |                                                                                                                                                                                               
  |===                                                                                                                                                                                      |   1%
  |                                                                                                                                                                                               
  |===                                                                                                                                                                                      |   2%
  |                                                                                                                                                                                               
  |====                                                                                                                                                                                     |   2%
  |                                                                                                                                                                                               
  |=====                                                                                                                                                                                    |   2%
  |                                                                                                                                                                                               
  |=====                                                                                                                                                                                    |   3%
  |                                                                                                                                                                                               
  |======                                                                                                                                                                                   |   3%
  |                                                                                                                                                                                               
  |======                                                                                                                                                                                   |   4%
  |                                                                                                                                                                                               
  |=======                                                                                                                                                                                  |   4%
  |                                                                                                                                                                                               
  |========                                                                                                                                                                                 |   4%
  |                                                                                                                                                                                               
  |========                                                                                                                                                                                 |   5%
  |                                                                                                                                                                                               
  |=========                                                                                                                                                                                |   5%
  |                                                                                                                                                                                               
  |==========                                                                                                                                                                               |   5%
  |                                                                                                                                                                                               
  |==========                                                                                                                                                                               |   6%
  |                                                                                                                                                                                               
  |===========                                                                                                                                                                              |   6%
  |                                                                                                                                                                                               
  |============                                                                                                                                                                             |   6%
  |                                                                                                                                                                                               
  |============                                                                                                                                                                             |   7%
  |                                                                                                                                                                                               
  |=============                                                                                                                                                                            |   7%
  |                                                                                                                                                                                               
  |==============                                                                                                                                                                           |   7%
  |                                                                                                                                                                                               
  |==============                                                                                                                                                                           |   8%
  |                                                                                                                                                                                               
  |===============                                                                                                                                                                          |   8%
  |                                                                                                                                                                                               
  |================                                                                                                                                                                         |   8%
  |                                                                                                                                                                                               
  |================                                                                                                                                                                         |   9%
  |                                                                                                                                                                                               
  |=================                                                                                                                                                                        |   9%
  |                                                                                                                                                                                               
  |==================                                                                                                                                                                       |   9%
  |                                                                                                                                                                                               
  |==================                                                                                                                                                                       |  10%
  |                                                                                                                                                                                               
  |===================                                                                                                                                                                      |  10%
  |                                                                                                                                                                                               
  |===================                                                                                                                                                                      |  11%
  |                                                                                                                                                                                               
  |====================                                                                                                                                                                     |  11%
  |                                                                                                                                                                                               
  |=====================                                                                                                                                                                    |  11%
  |                                                                                                                                                                                               
  |=====================                                                                                                                                                                    |  12%
  |                                                                                                                                                                                               
  |======================                                                                                                                                                                   |  12%
  |                                                                                                                                                                                               
  |=======================                                                                                                                                                                  |  12%
  |                                                                                                                                                                                               
  |=======================                                                                                                                                                                  |  13%
  |                                                                                                                                                                                               
  |========================                                                                                                                                                                 |  13%
  |                                                                                                                                                                                               
  |=========================                                                                                                                                                                |  13%
  |                                                                                                                                                                                               
  |=========================                                                                                                                                                                |  14%
  |                                                                                                                                                                                               
  |==========================                                                                                                                                                               |  14%
  |                                                                                                                                                                                               
  |===========================                                                                                                                                                              |  14%
  |                                                                                                                                                                                               
  |===========================                                                                                                                                                              |  15%
  |                                                                                                                                                                                               
  |============================                                                                                                                                                             |  15%
  |                                                                                                                                                                                               
  |=============================                                                                                                                                                            |  15%
  |                                                                                                                                                                                               
  |=============================                                                                                                                                                            |  16%
  |                                                                                                                                                                                               
  |==============================                                                                                                                                                           |  16%
  |                                                                                                                                                                                               
  |===============================                                                                                                                                                          |  16%
  |                                                                                                                                                                                               
  |===============================                                                                                                                                                          |  17%
  |                                                                                                                                                                                               
  |================================                                                                                                                                                         |  17%
  |                                                                                                                                                                                               
  |================================                                                                                                                                                         |  18%
  |                                                                                                                                                                                               
  |=================================                                                                                                                                                        |  18%
  |                                                                                                                                                                                               
  |==================================                                                                                                                                                       |  18%
  |                                                                                                                                                                                               
  |==================================                                                                                                                                                       |  19%
  |                                                                                                                                                                                               
  |===================================                                                                                                                                                      |  19%
  |                                                                                                                                                                                               
  |====================================                                                                                                                                                     |  19%
  |                                                                                                                                                                                               
  |====================================                                                                                                                                                     |  20%
  |                                                                                                                                                                                               
  |=====================================                                                                                                                                                    |  20%
  |                                                                                                                                                                                               
  |======================================                                                                                                                                                   |  20%
  |                                                                                                                                                                                               
  |======================================                                                                                                                                                   |  21%
  |                                                                                                                                                                                               
  |=======================================                                                                                                                                                  |  21%
  |                                                                                                                                                                                               
  |========================================                                                                                                                                                 |  21%
  |                                                                                                                                                                                               
  |========================================                                                                                                                                                 |  22%
  |                                                                                                                                                                                               
  |=========================================                                                                                                                                                |  22%
  |                                                                                                                                                                                               
  |==========================================                                                                                                                                               |  22%
  |                                                                                                                                                                                               
  |==========================================                                                                                                                                               |  23%
  |                                                                                                                                                                                               
  |===========================================                                                                                                                                              |  23%
  |                                                                                                                                                                                               
  |===========================================                                                                                                                                              |  24%
  |                                                                                                                                                                                               
  |============================================                                                                                                                                             |  24%
  |                                                                                                                                                                                               
  |=============================================                                                                                                                                            |  24%
  |                                                                                                                                                                                               
  |=============================================                                                                                                                                            |  25%
  |                                                                                                                                                                                               
  |==============================================                                                                                                                                           |  25%
  |                                                                                                                                                                                               
  |===============================================                                                                                                                                          |  25%
  |                                                                                                                                                                                               
  |===============================================                                                                                                                                          |  26%
  |                                                                                                                                                                                               
  |================================================                                                                                                                                         |  26%
  |                                                                                                                                                                                               
  |=================================================                                                                                                                                        |  26%
  |                                                                                                                                                                                               
  |=================================================                                                                                                                                        |  27%
  |                                                                                                                                                                                               
  |==================================================                                                                                                                                       |  27%
  |                                                                                                                                                                                               
  |===================================================                                                                                                                                      |  27%
  |                                                                                                                                                                                               
  |===================================================                                                                                                                                      |  28%
  |                                                                                                                                                                                               
  |====================================================                                                                                                                                     |  28%
  |                                                                                                                                                                                               
  |=====================================================                                                                                                                                    |  28%
  |                                                                                                                                                                                               
  |=====================================================                                                                                                                                    |  29%
  |                                                                                                                                                                                               
  |======================================================                                                                                                                                   |  29%
  |                                                                                                                                                                                               
  |=======================================================                                                                                                                                  |  29%
  |                                                                                                                                                                                               
  |=======================================================                                                                                                                                  |  30%
  |                                                                                                                                                                                               
  |========================================================                                                                                                                                 |  30%
  |                                                                                                                                                                                               
  |========================================================                                                                                                                                 |  31%
  |                                                                                                                                                                                               
  |=========================================================                                                                                                                                |  31%
  |                                                                                                                                                                                               
  |==========================================================                                                                                                                               |  31%
  |                                                                                                                                                                                               
  |==========================================================                                                                                                                               |  32%
  |                                                                                                                                                                                               
  |===========================================================                                                                                                                              |  32%
  |                                                                                                                                                                                               
  |============================================================                                                                                                                             |  32%
  |                                                                                                                                                                                               
  |============================================================                                                                                                                             |  33%
  |                                                                                                                                                                                               
  |=============================================================                                                                                                                            |  33%
  |                                                                                                                                                                                               
  |==============================================================                                                                                                                           |  33%
  |                                                                                                                                                                                               
  |==============================================================                                                                                                                           |  34%
  |                                                                                                                                                                                               
  |===============================================================                                                                                                                          |  34%
  |                                                                                                                                                                                               
  |================================================================                                                                                                                         |  34%
  |                                                                                                                                                                                               
  |================================================================                                                                                                                         |  35%
  |                                                                                                                                                                                               
  |=================================================================                                                                                                                        |  35%
  |                                                                                                                                                                                               
  |==================================================================                                                                                                                       |  35%
  |                                                                                                                                                                                               
  |==================================================================                                                                                                                       |  36%
  |                                                                                                                                                                                               
  |===================================================================                                                                                                                      |  36%
  |                                                                                                                                                                                               
  |====================================================================                                                                                                                     |  36%
  |                                                                                                                                                                                               
  |====================================================================                                                                                                                     |  37%
  |                                                                                                                                                                                               
  |=====================================================================                                                                                                                    |  37%
  |                                                                                                                                                                                               
  |=====================================================================                                                                                                                    |  38%
  |                                                                                                                                                                                               
  |======================================================================                                                                                                                   |  38%
  |                                                                                                                                                                                               
  |=======================================================================                                                                                                                  |  38%
  |                                                                                                                                                                                               
  |=======================================================================                                                                                                                  |  39%
  |                                                                                                                                                                                               
  |========================================================================                                                                                                                 |  39%
  |                                                                                                                                                                                               
  |=========================================================================                                                                                                                |  39%
  |                                                                                                                                                                                               
  |=========================================================================                                                                                                                |  40%
  |                                                                                                                                                                                               
  |==========================================================================                                                                                                               |  40%
  |                                                                                                                                                                                               
  |===========================================================================                                                                                                              |  40%
  |                                                                                                                                                                                               
  |===========================================================================                                                                                                              |  41%
  |                                                                                                                                                                                               
  |============================================================================                                                                                                             |  41%
  |                                                                                                                                                                                               
  |=============================================================================                                                                                                            |  41%
  |                                                                                                                                                                                               
  |=============================================================================                                                                                                            |  42%
  |                                                                                                                                                                                               
  |==============================================================================                                                                                                           |  42%
  |                                                                                                                                                                                               
  |===============================================================================                                                                                                          |  42%
  |                                                                                                                                                                                               
  |===============================================================================                                                                                                          |  43%
  |                                                                                                                                                                                               
  |================================================================================                                                                                                         |  43%
  |                                                                                                                                                                                               
  |================================================================================                                                                                                         |  44%
  |                                                                                                                                                                                               
  |=================================================================================                                                                                                        |  44%
  |                                                                                                                                                                                               
  |==================================================================================                                                                                                       |  44%
  |                                                                                                                                                                                               
  |==================================================================================                                                                                                       |  45%
  |                                                                                                                                                                                               
  |===================================================================================                                                                                                      |  45%
  |                                                                                                                                                                                               
  |====================================================================================                                                                                                     |  45%
  |                                                                                                                                                                                               
  |====================================================================================                                                                                                     |  46%
  |                                                                                                                                                                                               
  |=====================================================================================                                                                                                    |  46%
  |                                                                                                                                                                                               
  |======================================================================================                                                                                                   |  46%
  |                                                                                                                                                                                               
  |======================================================================================                                                                                                   |  47%
  |                                                                                                                                                                                               
  |=======================================================================================                                                                                                  |  47%
  |                                                                                                                                                                                               
  |========================================================================================                                                                                                 |  47%
  |                                                                                                                                                                                               
  |========================================================================================                                                                                                 |  48%
  |                                                                                                                                                                                               
  |=========================================================================================                                                                                                |  48%
  |                                                                                                                                                                                               
  |==========================================================================================                                                                                               |  48%
  |                                                                                                                                                                                               
  |==========================================================================================                                                                                               |  49%
  |                                                                                                                                                                                               
  |===========================================================================================                                                                                              |  49%

Save progress

# save.image(file = paste0(projectName, '.RData'))
saveRDS(seurat.object, file = paste0(projectName, "_raw.RDS"))

PCA

linear dimensional reduction. Default are based on VariableFeatures, but can be changed

seurat.object <- RunPCA(seurat.object, features = VariableFeatures(object = seurat.object))

Plot results

VizDimLoadings(seurat.object, dims = 1:6, nfeatures = 10, reduction = "pca", ncol = 2)

DimPlot colored by orig.ident

DimPlot(seurat.object, reduction = "pca", group.by = "orig.ident")

Let’s put in a concerted effort to pick the right dimensionality using the newest software

# jackstraw.dim <- 40
# seurat.object <- JackStraw(seurat.object, num.replicate = 100, dims = jackstraw.dim) #runs ~50 min
# seurat.object <- ScoreJackStraw(seurat.object, dims = 1:jackstraw.dim)
# save.image(paste0(projectName, ".RData"))

Draw dim.reduction plots

# JackStrawPlot(seurat.object, dims = 25:36)
ElbowPlot(seurat.object, ndims = 50)
percent.variance(seurat.object@reductions$pca@stdev)

Number of PCs describing X% of variance

ElbowPlot(seurat.object, ndims = 50)

percent.variance(seurat.object@reductions$pca@stdev)

Percent of PCs describing X% of variance (transcribed from above cell because I don’t know how to freeze results)

Num pcs for 80% variance: 12 Num pcs for 85% variance: 18 Num pcs for 90% variance: 26 Num pcs for 95% variance: 37

ID clusters based on different variances

Describe 80% of variance with 12 dimensions

Neighborhood and umap

set total.var <- 80%

tot.var <- percent.variance(seurat.object@reductions$pca@stdev, plot.var = FALSE, return.val = TRUE)
paste0("Num pcs for 80% variance: ", length(which(cumsum(tot.var) <= 80)))
[1] "Num pcs for 80% variance: 25"
paste0("Num pcs for 85% variance: ", length(which(cumsum(tot.var) <= 85)))
[1] "Num pcs for 85% variance: 30"
paste0("Num pcs for 90% variance: ", length(which(cumsum(tot.var) <= 90)))
[1] "Num pcs for 90% variance: 37"
paste0("Num pcs for 95% variance: ", length(which(cumsum(tot.var) <= 95)))
[1] "Num pcs for 95% variance: 43"

Plot UMAP

tot.var <- percent.variance(seurat.object@reductions$pca@stdev, plot.var = FALSE, return.val = TRUE)
ndims <- length(which(cumsum(tot.var) <= 80))

seurat.object <- FindNeighbors(seurat.object, dims = 1:ndims)
Computing nearest neighbor graph
Computing SNN
seurat.object <- FindClusters(seurat.object, resolution = 0.5)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 10627
Number of edges: 352668

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8185
Number of communities: 11
Elapsed time: 2 seconds
seurat.object <- RunUMAP(seurat.object, dims = 1: ndims)
Warning: The default method for RunUMAP has changed from calling Python UMAP via reticulate to the R-native UWOT using the cosine metric
To use Python UMAP via reticulate, set umap.method to 'umap-learn' and metric to 'correlation'
This message will be shown once per session
16:00:37 UMAP embedding parameters a = 0.9922 b = 1.112
16:00:37 Read 10627 rows and found 25 numeric columns
16:00:37 Using Annoy for neighbor search, n_neighbors = 30
16:00:37 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
16:00:38 Writing NN index file to temp file /var/folders/4f/fwrj6fnn1dn4g8wsf0zv563hjsvl24/T//RtmpFboagN/filed9154a56740a
16:00:38 Searching Annoy index using 1 thread, search_k = 3000
16:00:43 Annoy recall = 100%
16:00:43 Commencing smooth kNN distance calibration using 1 thread
16:00:44 Initializing from normalized Laplacian + noise
16:00:45 Commencing optimization for 200 epochs, with 456676 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
16:00:55 Optimization finished
for(x in c(0.5, 1, 1.5, 2, 2.5)){
    seurat.object <- FindClusters(seurat.object, resolution = x)
}
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 10627
Number of edges: 352668

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8185
Number of communities: 11
Elapsed time: 3 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 10627
Number of edges: 352668

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.7648
Number of communities: 17
Elapsed time: 2 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 10627
Number of edges: 352668

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.7276
Number of communities: 21
Elapsed time: 2 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 10627
Number of edges: 352668

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.6988
Number of communities: 24
Elapsed time: 2 seconds
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 10627
Number of edges: 352668

Running Louvain algorithm...
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.6750
Number of communities: 31
Elapsed time: 2 seconds
for (meta.col in colnames(seurat.object@meta.data)){
    if(grepl(pattern = ("RNA_snn_res"), x = meta.col)==TRUE){
        myplot <- DimPlot(seurat.object, 
                                            group.by = meta.col,
                                            reduction = "umap", 
                                            cols = color.palette
        ) + 
            ggtitle(paste0(projectName, " dim", ndims, "res", gsub("RNA_snn_res", "", meta.col) ))
        plot(myplot)
    }
}

Evaluate cluster stability

saveRDS(seurat.object, file = paste0(projectName, "_dim", ndims, ".RDS"))
clustree(seurat.object, prefix = "RNA_snn_res.", node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')
Warning: The `add` argument of `group_by()` is deprecated as of dplyr 1.0.0.
Please use the `.add` argument instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.

clustree(seurat.object, prefix = "RNA_snn_res.", expres = 'scale.data', node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')
clustree(seurat.object, prefix = "RNA_snn_res.", expres = 'counts', node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')

Describe 85% of variance with 18 dimensions

Neighborhood and umap

set total.var <- 85%

tot.var <- percent.variance(seurat.object@reductions$pca@stdev, plot.var = FALSE, return.val = TRUE)
ndims <- length(which(cumsum(tot.var) <= 85))

seurat.object <- FindNeighbors(seurat.object, dims = 1:ndims)
seurat.object <- FindClusters(seurat.object, resolution = 0.5)
seurat.object <- RunUMAP(seurat.object, dims = 1: ndims)

Plot UMAP

for(x in c(0.5, 1, 1.5, 2, 2.5)){
    seurat.object <- FindClusters(seurat.object, resolution = x)
}
for (meta.col in colnames(seurat.object@meta.data)){
    if(grepl(pattern = ("RNA_snn_res"), x = meta.col)==TRUE){
        myplot <- DimPlot(seurat.object, 
                                            group.by = meta.col,
                                            reduction = "umap", 
                                            cols = color.palette
        ) + 
            ggtitle(paste0(projectName, " dim", ndims, "res", gsub("RNA_snn_res", "", meta.col) ))
        plot(myplot)
    }
}

Generate statistics for each cluster/resolution combo

Evaluate cluster stability

Must ensure we have the right cluster stability, that is, cells that start in the same cluster tend to stay in the same cluster. If your data is over-clustered, cells will bounce between groups.

Following [this tutorial by Matt O.].https://towardsdatascience.com/10-tips-for-choosing-the-optimal-number-of-clusters-277e93d72d92. Previously my favourite has been Clustree, which gives a nice visual NB: For some reason clustree::clustree() didn’t work, whereas library(clustree) followed by clustree() did.

Describe 90% of variance with 26 dimensions

Neighborhood and umap

tot.var <- percent.variance(seurat.object@reductions$pca@stdev, plot.var = FALSE, return.val = TRUE)
ndims <- length(which(cumsum(tot.var) <= 90))

seurat.object <- FindNeighbors(seurat.object, dims = 1:ndims)
seurat.object <- FindClusters(seurat.object, resolution = 0.5)
seurat.object <- RunUMAP(seurat.object, dims = 1: ndims)

Plot UMAP

for(x in c(0.5, 1, 1.5, 2, 2.5)){
    seurat.object <- FindClusters(seurat.object, resolution = x)
}
for (meta.col in colnames(seurat.object@meta.data)){
    if(grepl(pattern = "RNA_snn_res", x = meta.col)==TRUE | grepl(pattern = "orig.ident", x = meta.col)==TRUE){
        myplot <- DimPlot(seurat.object, 
                                            group.by = meta.col,
                                            reduction = "umap", 
                                            pt.size = 1,
                                            cols = color.palette) + 
            ggtitle(paste0(projectName, " dim", ndims, "res.", gsub("RNA_snn_res.", "", meta.col) ))
        plot(myplot)
        png(filename = paste0(projectName, " dim", ndims, "res.", gsub("RNA_snn_res.", "", meta.col), "-umap.png"), height = 800, width = 800)
        plot(myplot)
        dev.off()
        myplot <- DimPlot(seurat.object, 
                                            group.by = meta.col,
                                            reduction = "umap", 
                                            pt.size = 1,
                                            cols = color.palette) + 
            facet_wrap(meta.col) + 
            ggtitle(paste0(projectName, " dim", ndims, "res.", gsub("RNA_snn_res.", "", meta.col)))
        
        png(filename = paste0(projectName, " dim", ndims, "res.", gsub("RNA_snn_res.", "", meta.col), "-umap_FacetRes.png"), height = 800, width = 800)
        plot(myplot)
        dev.off()
        
    }
}
saveRDS(seurat.object, file = paste0(projectName, "_dim", ndims, ".RDS"))

Generate statistics for each cluster/resolution combo

current_res <- 'RNA_snn_res.1'

cluster_ids <- sort(unique(seurat.object@meta.data[,current_res]))
counts_df <- data.frame(matrix(nrow = length(cluster_ids), ncol = 9))
rownames(counts_df) <- cluster_ids
colnames(counts_df) <- c("LSKm2", "CMPm2", "MEPm", "GMPm", "TotInClust", "PctClusLSK", "PctClusCMP", "PctClusMEP", "PctClusGMP")
for(id in cluster_ids){
    cell_value <- nrow(seurat.object@meta.data[(seurat.object@meta.data[current_res] == id) & 
                                                                                            (seurat.object@meta.data$orig.ident == "LSKm2"),])
    counts_df[id, "LSKm2"] = cell_value
    cell_value <- nrow(seurat.object@meta.data[(seurat.object@meta.data[current_res] == id) & 
                                                                                            (seurat.object@meta.data$orig.ident == "CMPm2"),])
    counts_df[id, "CMPm2"] = cell_value
    cell_value <- nrow(seurat.object@meta.data[(seurat.object@meta.data[current_res] == id) & 
                                                                                            (seurat.object@meta.data$orig.ident == "MEPm"),])
    counts_df[id, "MEPm"] = cell_value
    cell_value <- nrow(seurat.object@meta.data[(seurat.object@meta.data[current_res] == id) & 
                                                                                            (seurat.object@meta.data$orig.ident == "GMPm"),])
    counts_df[id, "GMPm"] = cell_value
    
}
counts_df["TotInClust"] <- rowSums(counts_df, na.rm = TRUE)
counts_df$PctClusLSK <- round(counts_df$LSKm2/counts_df$TotInClust, 3)*100
counts_df$PctClusCMP <- round(counts_df$CMPm2/counts_df$TotInClust, 3)*100
counts_df$PctClusMEP <- round(counts_df$MEPm/counts_df$TotInClust, 3)*100
counts_df$PctClusGMP <- round(counts_df$GMPm/counts_df$TotInClust, 3)*100
xlsx::write.xlsx(x = counts_df, 
                                 file = paste0(projectName, "CellCountPerClust",ndims, "res.1.xlsx"), 
                                 sheetName = "res1", 
                                 col.names = TRUE, 
                                 row.names = TRUE, 
                                 append = TRUE)


counts_df

Evaluate cluster stability

clustree(seurat.object, prefix = "RNA_snn_res.", node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')
png(filename = paste0(projectName, "_dim", ndims, "-clustree.png"), height = 800, width = 1600)
clustree(seurat.object, prefix = "RNA_snn_res.", node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')
dev.off()
clustree(seurat.object, prefix = "RNA_snn_res.", expres = 'data', node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')
clustree(seurat.object, prefix = "RNA_snn_res.", expres = 'scale.data', node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')
clustree(seurat.object, prefix = "RNA_snn_res.", expres = 'counts', node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')

Describe 95% of variance with 37 dimensions

Neighborhood and umap

tot.var <- percent.variance(seurat.object@reductions$pca@stdev, plot.var = FALSE, return.val = TRUE)
ndims <- length(which(cumsum(tot.var) <= 95))

seurat.object <- FindNeighbors(seurat.object, dims = 1:ndims)
seurat.object <- FindClusters(seurat.object, resolution = 0.5)
seurat.object <- RunUMAP(seurat.object, dims = 1: ndims)

Plot UMAP

for(x in c(0.5, 1, 1.5, 2, 2.5)){
    seurat.object <- FindClusters(seurat.object, resolution = x)
}
for (meta.col in colnames(seurat.object@meta.data)){
    if(grepl(pattern = ("RNA_snn_res"), x = meta.col)==TRUE){
        myplot <- DimPlot(seurat.object, 
                                            group.by = meta.col,
                                            reduction = "umap", 
                                            cols = color.palette
        ) + 
            ggtitle(paste0(projectName, " dim", ndims, "res", gsub("RNA_snn_res", "", meta.col) ))
        plot(myplot)
    }
}
saveRDS(seurat.object, file = paste0(projectName, "_dim", ndims, ".RDS"))

Generate statistics for each cluster/resolution combo

current_res <- 'RNA_snn_res.0.5'

cluster_ids <- sort(unique(seurat.object@meta.data[,current_res]))
counts_df <- data.frame(matrix(nrow = length(cluster_ids), ncol = 4))
rownames(counts_df) <- cluster_ids
colnames(counts_df) <- c("LSKm2", "CMPm2", "MEPm", "GMPm")
for(id in cluster_ids){
    cell_value <- nrow(seurat.object@meta.data[(seurat.object@meta.data[current_res] == id) & 
                                                                                            (seurat.object@meta.data$orig.ident == "LSKm2"),])
    counts_df[id, "LSKm2"] = cell_value
    cell_value <- nrow(seurat.object@meta.data[(seurat.object@meta.data[current_res] == id) & 
                                                                                            (seurat.object@meta.data$orig.ident == "LSKm2"),])
    counts_df[id, "CMPm2"] = cell_value
    cell_value <- nrow(seurat.object@meta.data[(seurat.object@meta.data[current_res] == id) & 
                                                                                            (seurat.object@meta.data$orig.ident == "MEPm"),])
    counts_df[id, "MEPm"] = cell_value
    cell_value <- nrow(seurat.object@meta.data[(seurat.object@meta.data[current_res] == id) & 
                                                                                            (seurat.object@meta.data$orig.ident == "GMPm"),])
    counts_df[id, "GMPm"] = cell_value
    
}

Evaluate cluster stability

clustree(seurat.object, prefix = "RNA_snn_res.", node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')
clustree(seurat.object, prefix = "RNA_snn_res.", expres = 'data', node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')
clustree(seurat.object, prefix = "RNA_snn_res.", expres = 'scale.data', node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')
clustree(seurat.object, prefix = "RNA_snn_res.", expres = 'counts', node_colour = "sc3_stability") + 
    scale_color_continuous(low = 'red3', high = 'white')

DGE

I think clusters from 90% variance at 0.5 and 1.0 resolution are most stable. We’ll do some statistics and DGE on that. Will also need to go back and play with SCTransform, since these are multiple cell types from multiple lanes. ## Load favourite dim reduction file

rds.file <- "msAggr_seurat_dim26.RDS"
seurat.object <- readRDS(rds.file)
ndims <- as.numeric(gsub("[^0-9]", "", stringr::str_split(rds.file, "_")[[1]][3]))

Set favourite resolution

object.res <- ".0.5"
Idents(seurat.object) <- paste0("RNA_snn_res", object.res)
length(levels(seurat.object@active.ident))

count number of filtered cells left from each population

# Number of filtered cells left in each pop
sapply(c("LSKm2", "CMPm2", "MEPm", "GMPm"), function(x) (c(nrow(seurat.object@meta.data[seurat.object@meta.data$orig.ident == x,]))))
par(mfrow = c(2, 2))
for (x in c("LSKm2", "CMPm2", "MEPm", "GMPm")){
    h = hist(seurat.object@meta.data[seurat.object@meta.data$orig.ident == x, 'percent.mt'], breaks = 30, plot = FALSE)
    h$density = h$counts/sum(h$counts)*100
    plot(h,freq=FALSE, main =  paste(x, "percent mitoC"), xlab = "percent mitoC", ylab = "Frequency")
}
par(mfrow = c(1,1))
VlnPlot(subset(seurat.object, subset = orig.ident == "MEPm"), 
                features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 1, pt.size = 0, fill.by = 'ident', flip = TRUE)

DGE w/ resolution = 0.5

Strt with comparing all clusters against all other clusters and write out cluster info calculate FindAllMarkers() for different idents and save to new file

# ident.list <- colnames(seurat.object@meta.data)[grepl("^RNA_snn", colnames(seurat.object@meta.data))]
ident.list <- c("RNA_snn_res.0.5", "RNA_snn_res.1")

for(tested.ident in ident.list){
    Idents(seurat.object) <- tested.ident
    all.markers <- FindAllMarkers(seurat.object)
    xlsx::write.xlsx(x = all.markers[,c("avg_log2FC", "p_val_adj", "cluster", "gene")], 
                                     file = paste0(projectName, "_FindALLMarkers_dim",ndims, "_allres.xlsx"), 
                                     sheetName = tested.ident, 
                                     col.names = TRUE, 
                                     row.names = FALSE, 
                                     append = TRUE)
}

Create FindAllMarkers() lists for GSEA

object.res.allmarkers <- FindAllMarkers(seurat.object)

Map HGNC symbols

Mouse2HumanTable <- Mouse2Human(object.res.allmarkers$gene)

HGNC <- with(Mouse2HumanTable, Mouse2HumanTable$HGNC[match(object.res.allmarkers$gene, Mouse2HumanTable$MGI)])
head(object.res.allmarkers)
object.res.allmarkers$HGNC <- HGNC
tail(object.res.allmarkers)
sig.res <- object.res.allmarkers[object.res.allmarkers$p_val_adj <= 0.05, ]
sig.res <- sig.res[c("avg_log2FC", "HGNC", "cluster")]
sig.res <- sig.res[!(sig.res$HGNC == "" | is.na(sig.res$HGNC)),] # GSEA will fail if there are any blanks or NAs in the table
sig.res <- sig.res[]
for(cluster in unique(sig.res$cluster)){
    print(paste("writing cluster", cluster))
    new.table <- sig.res[sig.res$cluster == cluster, c("HGNC", "avg_log2FC")]
    new.table <- new.table[order(-new.table$avg_log2FC), ]
    dir.create(paste0("RankList_res", object.res, "_findAll_hgnc/"), showWarnings = FALSE)
    write.table(new.table, file = paste0("RankList_res", object.res, "_findAll_hgnc/res", object.res, "cluster", cluster, ".rnk"), quote = FALSE, row.names = FALSE, col.names = TRUE, sep = "\t", )
    
}

calculate FindMarkers() that distinguish each cluster (might overlab between clusters)

# ident.list <- colnames(seurat.object@meta.data)[grepl("^RNA_snn", colnames(seurat.object@meta.data))]
ident.list <- c("RNA_snn_res.0.5", "RNA_snn_res.1")
for(tested.ident in ident.list){
    for (cluster in sort(as.numeric(levels(seurat.object@meta.data[[tested.ident]])))){
        cluster.markers <- FindMarkers(seurat.object, ident.1 = cluster)
        xlsx::write.xlsx(x = cluster.markers[,c("avg_log2FC", "p_val_adj")], 
                                         file = paste0(projectName, "_FindMarkers_dim", ndims, gsub("RNA_snn_", "", tested.ident), ".xlsx"), 
                                         sheetName = paste0("clst", cluster), 
                                         col.names = TRUE, 
                                         row.names = TRUE, 
                                         append = TRUE)
    }
}
for (cluster in sort(as.numeric(levels(seurat.object@meta.data[paste0("RNA_snn_res", object.res)])))){
    cluster.markers <- FindMarkers(seurat.object, ident.1 = cluster)
    xlsx::write.xlsx(x = cluster.markers[,c("avg_log2FC", "p_val_adj")], 
                                     file = paste0(projectName, "_FindMarkers_dim", ndims, "res", object.res, ".xlsx"), 
                                     sheetName = paste0("clst", cluster), 
                                     col.names = TRUE, 
                                     row.names = TRUE, 
                                     append = TRUE)
}

Notes on cluster stability

Cluster stability could be influenced by: * cells in each population (cellranger v6 includes more cells than cellranger v1, especially in MEP) * dimensionality is incorrect * ScaleData didnt account for regression factors (e.g., “nCounts_RNA” or “nFeatures_RNA”) * Did not consider cell cycle * Incorrect normalization/scaling method * Clustering is too strict or not strict enough * neighborhood analysis used wrong parameters * Should include mitoC filter (there’s a chunk of MEP w/ mitoC @ ~40%) * SCTransform accounts better for sources of variability

LS0tCnRpdGxlOiAibXNBZ2dyX3NldXJhdCIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGZpZ19oZWlnaHQ6IDYKLS0tCgpDcmVhdGluZyBuZXcgcGlwZWxpbmUgdXNpbmcgc2V1cmF0IHY0LjAuMiBhdmFpbGFibGUgMjAyMS4wNi4yMyAgCkltcG9ydGFudCBub3RlczoKCiogRklMVEVSSU5HIG9uIGBwZXJjZW50Lm10YCwgYnV0IE5PVCByZWdyZXNzaW5nIG9uIGBwZXJjZW50Lm10YAoqIFJlZ3Jlc3Npbmcgb24gYG5Db3VudHNfUk5BYCBhbmQgYG5GZWF0dXJlX1JOQWAKCiMgU2V0dXAKIyMgTG9hZCBsaWJyYXJpZXMgcmVxdWlyZWQgZm9yIFNldXJhdHY0CmBgYHtyIHNldHVwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9ICJ+L0Rlc2t0b3AvMTBYR2Vub21pY3NEYXRhL21zQWdncl9zY1JOQVNlcS9JbmRpdmlkdWFsUG9wcy8iKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjbHVzdHJlZSkKYGBgCiMjIFNvdXJjZSBmdW5jdGlvbnMKYGBge3J9CnNvdXJjZSgifi9EZXNrdG9wLzEwWEdlbm9taWNzRGF0YS9tc0FnZ3Jfc2NSTkFTZXEvUkZ1bmN0aW9ucy9yZWFkXzEwWEdlbm9taWNzX2RhdGEuUiIpCnNvdXJjZSgifi9EZXNrdG9wLzEwWEdlbm9taWNzRGF0YS9tc0FnZ3Jfc2NSTkFTZXEvUkZ1bmN0aW9ucy9QZXJjZW50VmFyaWFuY2UuUiIpCnNvdXJjZSgifi9EZXNrdG9wLzEwWEdlbm9taWNzRGF0YS9tc0FnZ3Jfc2NSTkFTZXEvUkZ1bmN0aW9ucy9Db2xvclBhbGV0dGUuUiIpCnNvdXJjZSgifi9EZXNrdG9wLzEwWEdlbm9taWNzRGF0YS9tc0FnZ3Jfc2NSTkFTZXEvUkZ1bmN0aW9ucy9Nb3VzZTJIdW1hbl9pZGNvbnZlcnNpb24uUiIpCmBgYAoKCiMgQSBub3RlIGFib3V0IHVzaW5nIFNDVHJhbnNmb3JtIHZlcnN1cyBgU2NhbGVEYXRhYApodHRwczovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvMy4xMC93b3JrZmxvd3MvdmlnbmV0dGVzL3NpbXBsZVNpbmdsZUNlbGwvaW5zdC9kb2MvYmF0Y2guaHRtbCM2Ml9mb3JfZ2VuZS1iYXNlZF9hbmFseXNlcwo+WW91IGNhbiBhbHNvIG5vcm1hbGl6ZSBhbmQgc2NhbGUgZGF0YSBmb3IgdGhlIFJOQSBhc3NheS4gVGhlcmUgYXJlIG51bWVyb3VzIHJlc291cmNlcyBvbiB0aGlzLCBidXQgQWFyb24gTHVuIGRlc2NyaWJlcyB3aHkgdGhlIG9yaWdpbmFsIGxvZy1ub3JtYWxpemVkIHZhbHVlcyBzaG91bGQgYmUgdXNlZCBmb3IgREUgYW5kIHZpc3VhbGl6YXRpb25zIG9mIGV4cHJlc3Npb24gcXVpdGUgd2VsbCBoZXJlOgo+Cj5Gb3IgZ2VuZS1iYXNlZCBwcm9jZWR1cmVzIGxpa2UgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gKERFKSBhbmFseXNlcyBvciBnZW5lIG5ldHdvcmsgY29uc3RydWN0aW9uLCBpdCBpcyBkZXNpcmFibGUgdG8gdXNlIHRoZSBvcmlnaW5hbCBsb2ctZXhwcmVzc2lvbiB2YWx1ZXMgb3IgY291bnRzLiBUaGUgY29ycmVjdGVkIHZhbHVlcyBhcmUgb25seSB1c2VkIHRvIG9idGFpbiBjZWxsLWxldmVsIHJlc3VsdHMgc3VjaCBhcyBjbHVzdGVycyBvciB0cmFqZWN0b3JpZXMuIEJhdGNoIGVmZmVjdHMgYXJlIGhhbmRsZWQgZXhwbGljaXRseSB1c2luZyBibG9ja2luZyB0ZXJtcyBvciB2aWEgYSBtZXRhLWFuYWx5c2lzIGFjcm9zcyBiYXRjaGVzLiBXZSBkbyBub3QgdXNlIHRoZSBjb3JyZWN0ZWQgdmFsdWVzIGRpcmVjdGx5IGluIGdlbmUtYmFzZWQgYW5hbHlzZXMsIGZvciB2YXJpb3VzIHJlYXNvbnM6Cj4KPkl0IGlzIHVzdWFsbHkgaW5hcHByb3ByaWF0ZSB0byBwZXJmb3JtIERFIGFuYWx5c2VzIG9uIGJhdGNoLWNvcnJlY3RlZCB2YWx1ZXMsIGR1ZSB0byB0aGUgZmFpbHVyZSB0byBtb2RlbCB0aGUgdW5jZXJ0YWludHkgb2YgdGhlIGNvcnJlY3Rpb24uIFRoaXMgdXN1YWxseSByZXN1bHRzIGluIGxvc3Mgb2YgdHlwZSBJIGVycm9yIGNvbnRyb2wsIGkuZS4sIG1vcmUgZmFsc2UgcG9zaXRpdmVzIHRoYW4gZXhwZWN0ZWQuCj4KPlRoZSBjb3JyZWN0aW9uIGRvZXMgbm90IHByZXNlcnZlIHRoZSBtZWFuLXZhcmlhbmNlIHJlbGF0aW9uc2hpcC4gQXBwbGljYXRpb25zIG9mIGNvbW1vbiBERSBtZXRob2RzIGxpa2UgZWRnZVIgb3IgbGltbWEgYXJlIHVubGlrZWx5IHRvIGJlIHZhbGlkLgo+Cj5CYXRjaCBjb3JyZWN0aW9uIG1heSAoY29ycmVjdGx5KSByZW1vdmUgYmlvbG9naWNhbCBkaWZmZXJlbmNlcyBiZXR3ZWVuIGJhdGNoZXMgaW4gdGhlIGNvdXJzZSBvZiBtYXBwaW5nIGFsbCBjZWxscyBvbnRvIGEgY29tbW9uIGNvb3JkaW5hdGUgc3lzdGVtLiBSZXR1cm5pbmcgdG8gdGhlIHVuY29ycmVjdGVkIGV4cHJlc3Npb24gdmFsdWVzIHByb3ZpZGVzIGFuIG9wcG9ydHVuaXR5IGZvciBkZXRlY3Rpbmcgc3VjaCBkaWZmZXJlbmNlcyBpZiB0aGV5IGFyZSBvZiBpbnRlcmVzdC4gQ29udmVyc2VseSwgaWYgdGhlIGJhdGNoIGNvcnJlY3Rpb24gbWFkZSBhIG1pc3Rha2UsIHRoZSB1c2Ugb2YgdGhlIHVuY29ycmVjdGVkIGV4cHJlc3Npb24gdmFsdWVzIHByb3ZpZGVzIGFuIGltcG9ydGFudCBzYW5pdHkgY2hlY2suCj4KPkluIGFkZGl0aW9uLCB0aGUgbm9ybWFsaXplZCB2YWx1ZXMgaW4gU0NUIGFuZCBpbnRlZ3JhdGVkIGFzc2F5cyBkb24ndCBuZWNlc3NhcnkgY29ycmVzcG9uZCB0byBwZXItZ2VuZSBleHByZXNzaW9uIHZhbHVlcyBhbnl3YXksIHJhdGhlciBjb250YWluaW5nIHJlc2lkdWFscyAoaW4gdGhlIGNhc2Ugb2YgdGhlIHNjYWxlLmRhdGEgc2xvdCBmb3IgZWFjaCkuCiMjIFNldCBnbG9iYWwgdmFyaWFibGVzCgpgYGB7cn0KcHJvamVjdE5hbWUgPC0gIkxTS1N1YnBvcCIKamFja3N0cmF3LmRpbSA8LSA0MApgYGAKCiMjIFN0b3JlIHNlc3Npb24gaW5mbwpgYGB7cn0Kc2luayhwYXN0ZTAocHJvamVjdE5hbWUsICJfc2Vzc2lvbkluZm8udHh0IikpCnNlc3Npb25JbmZvKCkKc2luaygpCmBgYAoKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnNldHdkKCJ+L0Rlc2t0b3AvMTBYR2Vub21pY3NEYXRhL2NlbGxSYW5nZXIvIikgIyB0ZW1wb3JhcmlseSBjaGFuZ2luZyB3ZCBvbmx5IHdvcmtzIGlmIHlvdSBydW4gdGhlIGVudGlyZSBjaHVuayBhdCBvbmNlCmRhdGFfZmlsZS5saXN0IDwtIHJlYWRfMTBYR2Vub21pY3NfZGF0YShzYW1wbGUubGlzdCA9IGMoIkxTS20yIikpCmRhdGEub2JqZWN0PC1SZWFkMTBYKGRhdGFfZmlsZS5saXN0KQpgYGAKCgoKYGBge3J9CnNldXJhdC5vYmplY3Q8LSBDcmVhdGVTZXVyYXRPYmplY3QoY291bnRzID0gZGF0YS5vYmplY3QsIG1pbi5jZWxscyA9IDMsIG1pbi5nZW5lcyA9IDIwMCwgcHJvamVjdCA9IHByb2plY3ROYW1lKQpgYGAKCkNsZWFuIHVwIHRvIGZyZWUgbWVtb3J5CgpgYGB7cn0KcmVtb3ZlKGRhdGEub2JqZWN0KQpgYGAKCgpBZGQgbWl0b2Nob25kcmlhbCBtZXRhZGF0YSBhbmQgcGxvdCBzb21lIGJhc2ljIGZlYXR1cmVzCmBgYHtyfQpzZXVyYXQub2JqZWN0W1sicGVyY2VudC5tdCJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChzZXVyYXQub2JqZWN0LCBwYXR0ZXJuID0gIl5tdC0iKQpWbG5QbG90KHNldXJhdC5vYmplY3QsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiwgIm5Db3VudF9STkEiLCAicGVyY2VudC5tdCIpLCBuY29sID0gMywgcHQuc2l6ZSA9IDAsIGZpbGwuYnkgPSAnb3JpZy5pZGVudCcsICkKYGBgCgoKYGBge3IgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9Mn0KcGxvdDEgPC0gRmVhdHVyZVNjYXR0ZXIoc2V1cmF0Lm9iamVjdCwgZmVhdHVyZTEgPSAibkNvdW50X1JOQSIsIGZlYXR1cmUyID0gInBlcmNlbnQubXQiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IiwgcHQuc2l6ZSA9IDAuMDEpCnBsb3QyIDwtIEZlYXR1cmVTY2F0dGVyKHNldXJhdC5vYmplY3QsIGZlYXR1cmUxID0gIm5Db3VudF9STkEiLCBmZWF0dXJlMiA9ICJuRmVhdHVyZV9STkEiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IiwgcHQuc2l6ZSA9IDAuMDEpCnBsb3QxICsgcGxvdDIKYGBgCgoKcmVtb3ZlIGxvdyBxdWFsaXR5IGNlbGxzCnJlcXVpcmU6IG5GZWF0dXJlX1JOQSBiZXR3ZWVuIDIwMCBhbmQgNDAwMCAoaW5jbHVzaXZlKQpyZXF1aXJlOiBwZXJjZW50Lm10IDw9IDUKCmBgYHtyfQpwcmludChwYXN0ZSgib3JpZ2luYWwgb2JqZWN0OiIsIG5yb3coc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGEpLCAiY2VsbHMiLCBzZXAgPSAiICIpKQpzZXVyYXQub2JqZWN0IDwtIHN1YnNldChzZXVyYXQub2JqZWN0LCAKCQkJCQkJCQkJCQkJc3Vic2V0ID0gbkZlYXR1cmVfUk5BID49MjAwICYgCgkJCQkJCQkJCQkJCQluRmVhdHVyZV9STkEgPD0gNDAwMCAmIAoJCQkJCQkJCQkJCQkJcGVyY2VudC5tdCA8PSA1CikKcHJpbnQocGFzdGUoIm5ldyBvYmplY3Q6IiwgbnJvdyhzZXVyYXQub2JqZWN0QG1ldGEuZGF0YSksICJjZWxscyIsIHNlcCA9ICIgIikpCmBgYAoKCgojIyBOb3JtYWxpemF0aW9uCgpTdHJ1Z2dsaW5nIHRvIHdyYXAgbXkgaGVhZCBhcm91bmQgdGhpcyBvbmUuIEl0IHNlZW1zIHRoYXQgU0NUcmFuc2Zvcm0gaXMgYmVzdCBmb3IgYmF0Y2ggY29ycmVjdGlvbiwgYnV0IGBOb3JtYWxpemVEYXRhYCBhbmQgYFNjYWxlRGF0YWAgYXJlIGJlc3QgZm9yIERHRS4gU2V2ZXJhbCB2aWduZXR0ZXMgaGF2ZSBwZXJmb3JtZWQgYm90aAoKYHNlbGVjdGlvbi5tZXRob2QJCkhvdyB0byBjaG9vc2UgdG9wIHZhcmlhYmxlIGZlYXR1cmVzLiBDaG9vc2Ugb25lIG9mIDoKCnZzdDogRmlyc3QsIGZpdHMgYSBsaW5lIHRvIHRoZSByZWxhdGlvbnNoaXAgb2YgbG9nKHZhcmlhbmNlKSBhbmQgbG9nKG1lYW4pIHVzaW5nIGxvY2FsIHBvbHlub21pYWwgcmVncmVzc2lvbiAobG9lc3MpLiBUaGVuIHN0YW5kYXJkaXplcyB0aGUgZmVhdHVyZSB2YWx1ZXMgdXNpbmcgdGhlIG9ic2VydmVkIG1lYW4gYW5kIGV4cGVjdGVkIHZhcmlhbmNlIChnaXZlbiBieSB0aGUgZml0dGVkIGxpbmUpLiBGZWF0dXJlIHZhcmlhbmNlIGlzIHRoZW4gY2FsY3VsYXRlZCBvbiB0aGUgc3RhbmRhcmRpemVkIHZhbHVlcyBhZnRlciBjbGlwcGluZyB0byBhIG1heGltdW0gKHNlZSBjbGlwLm1heCBwYXJhbWV0ZXIpLgoKbWVhbi52YXIucGxvdCAobXZwKTogRmlyc3QsIHVzZXMgYSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgYXZlcmFnZSBleHByZXNzaW9uIChtZWFuLmZ1bmN0aW9uKSBhbmQgZGlzcGVyc2lvbiAoZGlzcGVyc2lvbi5mdW5jdGlvbikgZm9yIGVhY2ggZmVhdHVyZS4gTmV4dCwgZGl2aWRlcyBmZWF0dXJlcyBpbnRvIG51bS5iaW4gKGRlYWZ1bHQgMjApIGJpbnMgYmFzZWQgb24gdGhlaXIgYXZlcmFnZSBleHByZXNzaW9uLCBhbmQgY2FsY3VsYXRlcyB6LXNjb3JlcyBmb3IgZGlzcGVyc2lvbiB3aXRoaW4gZWFjaCBiaW4uIFRoZSBwdXJwb3NlIG9mIHRoaXMgaXMgdG8gaWRlbnRpZnkgdmFyaWFibGUgZmVhdHVyZXMgd2hpbGUgY29udHJvbGxpbmcgZm9yIHRoZSBzdHJvbmcgcmVsYXRpb25zaGlwIGJldHdlZW4gdmFyaWFiaWxpdHkgYW5kIGF2ZXJhZ2UgZXhwcmVzc2lvbi4KCmRpc3BlcnNpb24gKGRpc3ApOiBzZWxlY3RzIHRoZSBnZW5lcyB3aXRoIHRoZSBoaWdoZXN0IGRpc3BlcnNpb24gdmFsdWVzYAoKCgoKYGBge3J9CnNldXJhdC5vYmplY3QgPC0gTm9ybWFsaXplRGF0YShzZXVyYXQub2JqZWN0LCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCkKYGBgCgoKCgoKRmluZCB2YXJpYWJsZSBmZWF0dXJlcwpgYGB7ciBmaWcud2lkdGggPSA1LCBmaWcuaGVpZ2h0ID0gMn0Kc2V1cmF0Lm9iamVjdCA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhzZXVyYXQub2JqZWN0LCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCnRvcDEwIDwtIGhlYWQoVmFyaWFibGVGZWF0dXJlcyhzZXVyYXQub2JqZWN0KSwgMTApCnBsb3QxIDwtIFZhcmlhYmxlRmVhdHVyZVBsb3Qoc2V1cmF0Lm9iamVjdCkKcGxvdDIgPC0gTGFiZWxQb2ludHMocGxvdCA9IHBsb3QxLCBwb2ludHMgPSB0b3AxMCwgcmVwZWwgPSBUUlVFKQpwbG90MSArIHBsb3QyCmBgYAoKU2NhbGUgZGF0YSAobGluZWFyIHRyYW5zZm9ybWF0aW9uKQoKYGBge3J9CmFsbC5nZW5lcyA8LSByb3duYW1lcyhzZXVyYXQub2JqZWN0KQpzZXVyYXQub2JqZWN0IDwtIFNjYWxlRGF0YShzZXVyYXQub2JqZWN0LCBmZWF0dXJlcyA9IGFsbC5nZW5lcywgdmFycy50by5yZWdyZXNzID0gYygibkNvdW50X1JOQSIsICJuRmVhdHVyZV9STkEiKSkKYGBgCgoKIyMjIFNhdmUgcHJvZ3Jlc3MKCmBgYHtyfQojIHNhdmUuaW1hZ2UoZmlsZSA9IHBhc3RlMChwcm9qZWN0TmFtZSwgJy5SRGF0YScpKQpzYXZlUkRTKHNldXJhdC5vYmplY3QsIGZpbGUgPSBwYXN0ZTAocHJvamVjdE5hbWUsICJfcmF3LlJEUyIpKQpgYGAKCgojIyBQQ0EKCmxpbmVhciBkaW1lbnNpb25hbCByZWR1Y3Rpb24uIERlZmF1bHQgYXJlIGJhc2VkIG9uIFZhcmlhYmxlRmVhdHVyZXMsIGJ1dCBjYW4gYmUgY2hhbmdlZAoKYGBge3J9CnNldXJhdC5vYmplY3QgPC0gUnVuUENBKHNldXJhdC5vYmplY3QsIGZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhvYmplY3QgPSBzZXVyYXQub2JqZWN0KSkKYGBgClBsb3QgcmVzdWx0cwpgYGB7ciBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQpWaXpEaW1Mb2FkaW5ncyhzZXVyYXQub2JqZWN0LCBkaW1zID0gMTo2LCBuZmVhdHVyZXMgPSAxMCwgcmVkdWN0aW9uID0gInBjYSIsIG5jb2wgPSAyKQpgYGAKCkRpbVBsb3QgY29sb3JlZCBieSBvcmlnLmlkZW50CmBgYHtyfQpEaW1QbG90KHNldXJhdC5vYmplY3QsIHJlZHVjdGlvbiA9ICJwY2EiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikKYGBgCkxldCdzIHB1dCBpbiBhIGNvbmNlcnRlZCBlZmZvcnQgdG8gcGljayB0aGUgcmlnaHQgZGltZW5zaW9uYWxpdHkgdXNpbmcgdGhlIG5ld2VzdCBzb2Z0d2FyZQpgYGB7cn0KIyBqYWNrc3RyYXcuZGltIDwtIDQwCiMgc2V1cmF0Lm9iamVjdCA8LSBKYWNrU3RyYXcoc2V1cmF0Lm9iamVjdCwgbnVtLnJlcGxpY2F0ZSA9IDEwMCwgZGltcyA9IGphY2tzdHJhdy5kaW0pICNydW5zIH41MCBtaW4KIyBzZXVyYXQub2JqZWN0IDwtIFNjb3JlSmFja1N0cmF3KHNldXJhdC5vYmplY3QsIGRpbXMgPSAxOmphY2tzdHJhdy5kaW0pCiMgc2F2ZS5pbWFnZShwYXN0ZTAocHJvamVjdE5hbWUsICIuUkRhdGEiKSkKYGBgCkRyYXcgZGltLnJlZHVjdGlvbiBwbG90cwpgYGB7cn0KIyBKYWNrU3RyYXdQbG90KHNldXJhdC5vYmplY3QsIGRpbXMgPSAyNTozNikKYGBgCmBgYHtyLCBmaWd1cmVzLXNpZGUsIGZpZy5zaG93PSdob2xkJywgb3V0LndpZHRoPSI1MCUifQpFbGJvd1Bsb3Qoc2V1cmF0Lm9iamVjdCwgbmRpbXMgPSA1MCkKcGVyY2VudC52YXJpYW5jZShzZXVyYXQub2JqZWN0QHJlZHVjdGlvbnMkcGNhQHN0ZGV2KQpgYGAKTnVtYmVyIG9mIFBDcyBkZXNjcmliaW5nIFglIG9mIHZhcmlhbmNlCmBgYHtyfQp0b3QudmFyIDwtIHBlcmNlbnQudmFyaWFuY2Uoc2V1cmF0Lm9iamVjdEByZWR1Y3Rpb25zJHBjYUBzdGRldiwgcGxvdC52YXIgPSBGQUxTRSwgcmV0dXJuLnZhbCA9IFRSVUUpCnBhc3RlMCgiTnVtIHBjcyBmb3IgODAlIHZhcmlhbmNlOiAiLCBsZW5ndGgod2hpY2goY3Vtc3VtKHRvdC52YXIpIDw9IDgwKSkpCnBhc3RlMCgiTnVtIHBjcyBmb3IgODUlIHZhcmlhbmNlOiAiLCBsZW5ndGgod2hpY2goY3Vtc3VtKHRvdC52YXIpIDw9IDg1KSkpCnBhc3RlMCgiTnVtIHBjcyBmb3IgOTAlIHZhcmlhbmNlOiAiLCBsZW5ndGgod2hpY2goY3Vtc3VtKHRvdC52YXIpIDw9IDkwKSkpCnBhc3RlMCgiTnVtIHBjcyBmb3IgOTUlIHZhcmlhbmNlOiAiLCBsZW5ndGgod2hpY2goY3Vtc3VtKHRvdC52YXIpIDw9IDk1KSkpCgpgYGAKClBlcmNlbnQgb2YgUENzIGRlc2NyaWJpbmcgWCUgb2YgdmFyaWFuY2UgKHRyYW5zY3JpYmVkIGZyb20gYWJvdmUgY2VsbCBiZWNhdXNlIEkgZG9uJ3Qga25vdyBob3cgdG8gZnJlZXplIHJlc3VsdHMpCgpOdW0gcGNzIGZvciA4MCUgdmFyaWFuY2U6IDEyCk51bSBwY3MgZm9yIDg1JSB2YXJpYW5jZTogMTgKTnVtIHBjcyBmb3IgOTAlIHZhcmlhbmNlOiAyNgpOdW0gcGNzIGZvciA5NSUgdmFyaWFuY2U6IDM3CgojIElEIGNsdXN0ZXJzIGJhc2VkIG9uIGRpZmZlcmVudCB2YXJpYW5jZXMKIyMgRGVzY3JpYmUgODAlIG9mIHZhcmlhbmNlIHdpdGggMTIgZGltZW5zaW9ucwoKIyMjIE5laWdoYm9yaG9vZCBhbmQgdW1hcApzZXQgdG90YWwudmFyIDwtIDgwJQpgYGB7cn0KdG90LnZhciA8LSBwZXJjZW50LnZhcmlhbmNlKHNldXJhdC5vYmplY3RAcmVkdWN0aW9ucyRwY2FAc3RkZXYsIHBsb3QudmFyID0gRkFMU0UsIHJldHVybi52YWwgPSBUUlVFKQpuZGltcyA8LSBsZW5ndGgod2hpY2goY3Vtc3VtKHRvdC52YXIpIDw9IDgwKSkKCnNldXJhdC5vYmplY3QgPC0gRmluZE5laWdoYm9ycyhzZXVyYXQub2JqZWN0LCBkaW1zID0gMTpuZGltcykKc2V1cmF0Lm9iamVjdCA8LSBGaW5kQ2x1c3RlcnMoc2V1cmF0Lm9iamVjdCwgcmVzb2x1dGlvbiA9IDAuNSkKc2V1cmF0Lm9iamVjdCA8LSBSdW5VTUFQKHNldXJhdC5vYmplY3QsIGRpbXMgPSAxOiBuZGltcykKCmBgYApQbG90IFVNQVAKCmBgYHtyfQpmb3IoeCBpbiBjKDAuNSwgMSwgMS41LCAyLCAyLjUpKXsKCXNldXJhdC5vYmplY3QgPC0gRmluZENsdXN0ZXJzKHNldXJhdC5vYmplY3QsIHJlc29sdXRpb24gPSB4KQp9CmBgYAoKYGBge3J9CmZvciAobWV0YS5jb2wgaW4gY29sbmFtZXMoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGEpKXsKCWlmKGdyZXBsKHBhdHRlcm4gPSAoIlJOQV9zbm5fcmVzIiksIHggPSBtZXRhLmNvbCk9PVRSVUUpewoJCW15cGxvdCA8LSBEaW1QbG90KHNldXJhdC5vYmplY3QsIAoJCQkJCQkJCQkJCWdyb3VwLmJ5ID0gbWV0YS5jb2wsCgkJCQkJCQkJCQkJcmVkdWN0aW9uID0gInVtYXAiLCAKCQkJCQkJCQkJCQljb2xzID0gY29sb3IucGFsZXR0ZQoJCSkgKyAKCQkJZ2d0aXRsZShwYXN0ZTAocHJvamVjdE5hbWUsICIgZGltIiwgbmRpbXMsICJyZXMiLCBnc3ViKCJSTkFfc25uX3JlcyIsICIiLCBtZXRhLmNvbCkgKSkKCQlwbG90KG15cGxvdCkKCX0KfQpgYGAKCmBgYHtyfQpzYXZlUkRTKHNldXJhdC5vYmplY3QsIGZpbGUgPSBwYXN0ZTAocHJvamVjdE5hbWUsICJfZGltIiwgbmRpbXMsICIuUkRTIikpCmBgYAoKIyMjIEV2YWx1YXRlIGNsdXN0ZXIgc3RhYmlsaXR5CmBgYHtyIGZpZy5oZWlnaHQ9NX0KY2x1c3RyZWUoc2V1cmF0Lm9iamVjdCwgcHJlZml4ID0gIlJOQV9zbm5fcmVzLiIsIG5vZGVfY29sb3VyID0gInNjM19zdGFiaWxpdHkiKSArIAoJc2NhbGVfY29sb3JfY29udGludW91cyhsb3cgPSAncmVkMycsIGhpZ2ggPSAnd2hpdGUnKQpgYGAKCgoKYGBge3IgZmlnLmhlaWdodD01fQpjbHVzdHJlZShzZXVyYXQub2JqZWN0LCBwcmVmaXggPSAiUk5BX3Nubl9yZXMuIiwgZXhwcmVzID0gJ2RhdGEnLCBub2RlX2NvbG91ciA9ICJzYzNfc3RhYmlsaXR5IikgKyAKCXNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93ID0gJ3JlZDMnLCBoaWdoID0gJ3doaXRlJykKYGBgCgoKYGBge3IgZmlnLmhlaWdodD01fQpjbHVzdHJlZShzZXVyYXQub2JqZWN0LCBwcmVmaXggPSAiUk5BX3Nubl9yZXMuIiwgZXhwcmVzID0gJ3NjYWxlLmRhdGEnLCBub2RlX2NvbG91ciA9ICJzYzNfc3RhYmlsaXR5IikgKyAKCXNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93ID0gJ3JlZDMnLCBoaWdoID0gJ3doaXRlJykKYGBgCgoKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KY2x1c3RyZWUoc2V1cmF0Lm9iamVjdCwgcHJlZml4ID0gIlJOQV9zbm5fcmVzLiIsIGV4cHJlcyA9ICdjb3VudHMnLCBub2RlX2NvbG91ciA9ICJzYzNfc3RhYmlsaXR5IikgKyAKCXNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93ID0gJ3JlZDMnLCBoaWdoID0gJ3doaXRlJykKYGBgCgoKCgoKCgoKCgoKCgojIyBEZXNjcmliZSA4NSUgb2YgdmFyaWFuY2Ugd2l0aCAxOCBkaW1lbnNpb25zCgojIyMgTmVpZ2hib3Job29kIGFuZCB1bWFwCnNldCB0b3RhbC52YXIgPC0gODUlCmBgYHtyfQp0b3QudmFyIDwtIHBlcmNlbnQudmFyaWFuY2Uoc2V1cmF0Lm9iamVjdEByZWR1Y3Rpb25zJHBjYUBzdGRldiwgcGxvdC52YXIgPSBGQUxTRSwgcmV0dXJuLnZhbCA9IFRSVUUpCm5kaW1zIDwtIGxlbmd0aCh3aGljaChjdW1zdW0odG90LnZhcikgPD0gODUpKQoKc2V1cmF0Lm9iamVjdCA8LSBGaW5kTmVpZ2hib3JzKHNldXJhdC5vYmplY3QsIGRpbXMgPSAxOm5kaW1zKQpzZXVyYXQub2JqZWN0IDwtIEZpbmRDbHVzdGVycyhzZXVyYXQub2JqZWN0LCByZXNvbHV0aW9uID0gMC41KQpzZXVyYXQub2JqZWN0IDwtIFJ1blVNQVAoc2V1cmF0Lm9iamVjdCwgZGltcyA9IDE6IG5kaW1zKQoKYGBgClBsb3QgVU1BUAoKYGBge3J9CmZvcih4IGluIGMoMC41LCAxLCAxLjUsIDIsIDIuNSkpewoJc2V1cmF0Lm9iamVjdCA8LSBGaW5kQ2x1c3RlcnMoc2V1cmF0Lm9iamVjdCwgcmVzb2x1dGlvbiA9IHgpCn0KYGBgCgpgYGB7cn0KZm9yIChtZXRhLmNvbCBpbiBjb2xuYW1lcyhzZXVyYXQub2JqZWN0QG1ldGEuZGF0YSkpewoJaWYoZ3JlcGwocGF0dGVybiA9ICgiUk5BX3Nubl9yZXMiKSwgeCA9IG1ldGEuY29sKT09VFJVRSl7CgkJbXlwbG90IDwtIERpbVBsb3Qoc2V1cmF0Lm9iamVjdCwgCgkJCQkJCQkJCQkJZ3JvdXAuYnkgPSBtZXRhLmNvbCwKCQkJCQkJCQkJCQlyZWR1Y3Rpb24gPSAidW1hcCIsIAoJCQkJCQkJCQkJCWNvbHMgPSBjb2xvci5wYWxldHRlCgkJKSArIAoJCQlnZ3RpdGxlKHBhc3RlMChwcm9qZWN0TmFtZSwgIiBkaW0iLCBuZGltcywgInJlcyIsIGdzdWIoIlJOQV9zbm5fcmVzIiwgIiIsIG1ldGEuY29sKSApKQoJCXBsb3QobXlwbG90KQoJfQp9CmBgYAoKYGBge3J9CnNhdmVSRFMoc2V1cmF0Lm9iamVjdCwgZmlsZSA9IHBhc3RlMChwcm9qZWN0TmFtZSwgIl9kaW0iLCBuZGltcywgIi5SRFMiKSkKYGBgCgpHZW5lcmF0ZSBzdGF0aXN0aWNzIGZvciBlYWNoIGNsdXN0ZXIvcmVzb2x1dGlvbiBjb21ibwpgYGB7cn0KY3VycmVudF9yZXMgPC0gJ1JOQV9zbm5fcmVzLjAuNScKCmNsdXN0ZXJfaWRzIDwtIHNvcnQodW5pcXVlKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhWyxjdXJyZW50X3Jlc10pKQpjb3VudHNfZGYgPC0gZGF0YS5mcmFtZShtYXRyaXgobnJvdyA9IGxlbmd0aChjbHVzdGVyX2lkcyksIG5jb2wgPSA0KSkKcm93bmFtZXMoY291bnRzX2RmKSA8LSBjbHVzdGVyX2lkcwpjb2xuYW1lcyhjb3VudHNfZGYpIDwtIGMoIkxTS20yIiwgIkNNUG0yIiwgIk1FUG0iLCAiR01QbSIpCmZvcihpZCBpbiBjbHVzdGVyX2lkcyl7CgljZWxsX3ZhbHVlIDwtIG5yb3coc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhW2N1cnJlbnRfcmVzXSA9PSBpZCkgJiAKCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSAJKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhJG9yaWcuaWRlbnQgPT0gIkxTS20yIiksXSkKCWNvdW50c19kZltpZCwgIkxTS20yIl0gPSBjZWxsX3ZhbHVlCgljZWxsX3ZhbHVlIDwtIG5yb3coc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhW2N1cnJlbnRfcmVzXSA9PSBpZCkgJiAKCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSAJKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhJG9yaWcuaWRlbnQgPT0gIkxTS20yIiksXSkKCWNvdW50c19kZltpZCwgIkNNUG0yIl0gPSBjZWxsX3ZhbHVlCgljZWxsX3ZhbHVlIDwtIG5yb3coc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhW2N1cnJlbnRfcmVzXSA9PSBpZCkgJiAKCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSAJKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhJG9yaWcuaWRlbnQgPT0gIk1FUG0iKSxdKQoJY291bnRzX2RmW2lkLCAiTUVQbSJdID0gY2VsbF92YWx1ZQoJY2VsbF92YWx1ZSA8LSBucm93KHNldXJhdC5vYmplY3RAbWV0YS5kYXRhWyhzZXVyYXQub2JqZWN0QG1ldGEuZGF0YVtjdXJyZW50X3Jlc10gPT0gaWQpICYgCgkJCQkJCQkJCQkJCQkJCQkJCQkJCQkgCShzZXVyYXQub2JqZWN0QG1ldGEuZGF0YSRvcmlnLmlkZW50ID09ICJHTVBtIiksXSkKCWNvdW50c19kZltpZCwgIkdNUG0iXSA9IGNlbGxfdmFsdWUKCQp9CgpgYGAKCgojIyMgRXZhbHVhdGUgY2x1c3RlciBzdGFiaWxpdHkKTXVzdCBlbnN1cmUgd2UgaGF2ZSB0aGUgcmlnaHQgY2x1c3RlciBzdGFiaWxpdHksIHRoYXQgaXMsIGNlbGxzIHRoYXQgc3RhcnQgaW4gdGhlIHNhbWUgY2x1c3RlciB0ZW5kIHRvIHN0YXkgaW4gdGhlIHNhbWUgY2x1c3Rlci4gSWYgeW91ciBkYXRhIGlzIG92ZXItY2x1c3RlcmVkLCBjZWxscyB3aWxsIGJvdW5jZSBiZXR3ZWVuIGdyb3Vwcy4KCkZvbGxvd2luZyBbdGhpcyB0dXRvcmlhbCBieSBNYXR0IE8uXS5odHRwczovL3Rvd2FyZHNkYXRhc2NpZW5jZS5jb20vMTAtdGlwcy1mb3ItY2hvb3NpbmctdGhlLW9wdGltYWwtbnVtYmVyLW9mLWNsdXN0ZXJzLTI3N2U5M2Q3MmQ5Mi4KUHJldmlvdXNseSBteSBmYXZvdXJpdGUgaGFzIGJlZW4gQ2x1c3RyZWUsIHdoaWNoIGdpdmVzIGEgbmljZSB2aXN1YWwKTkI6IEZvciBzb21lIHJlYXNvbiBgY2x1c3RyZWU6OmNsdXN0cmVlKClgIGRpZG4ndCB3b3JrLCB3aGVyZWFzIGBsaWJyYXJ5KGNsdXN0cmVlKWAgZm9sbG93ZWQgYnkgYGNsdXN0cmVlKClgIGRpZC4KCmBgYHtyIGZpZy5oZWlnaHQ9NX0KY2x1c3RyZWUoc2V1cmF0Lm9iamVjdCwgcHJlZml4ID0gIlJOQV9zbm5fcmVzLiIsIG5vZGVfY29sb3VyID0gInNjM19zdGFiaWxpdHkiKSArIAoJc2NhbGVfY29sb3JfY29udGludW91cyhsb3cgPSAncmVkMycsIGhpZ2ggPSAnd2hpdGUnKQpgYGAKCgoKCgoKIyMgRGVzY3JpYmUgOTAlIG9mIHZhcmlhbmNlIHdpdGggMjYgZGltZW5zaW9ucwoKIyMjIE5laWdoYm9yaG9vZCBhbmQgdW1hcApgYGB7cn0KdG90LnZhciA8LSBwZXJjZW50LnZhcmlhbmNlKHNldXJhdC5vYmplY3RAcmVkdWN0aW9ucyRwY2FAc3RkZXYsIHBsb3QudmFyID0gRkFMU0UsIHJldHVybi52YWwgPSBUUlVFKQpuZGltcyA8LSBsZW5ndGgod2hpY2goY3Vtc3VtKHRvdC52YXIpIDw9IDkwKSkKCnNldXJhdC5vYmplY3QgPC0gRmluZE5laWdoYm9ycyhzZXVyYXQub2JqZWN0LCBkaW1zID0gMTpuZGltcykKc2V1cmF0Lm9iamVjdCA8LSBGaW5kQ2x1c3RlcnMoc2V1cmF0Lm9iamVjdCwgcmVzb2x1dGlvbiA9IDAuNSkKc2V1cmF0Lm9iamVjdCA8LSBSdW5VTUFQKHNldXJhdC5vYmplY3QsIGRpbXMgPSAxOiBuZGltcykKCmBgYApQbG90IFVNQVAKCmBgYHtyfQpmb3IoeCBpbiBjKDAuNSwgMSwgMS41LCAyLCAyLjUpKXsKCXNldXJhdC5vYmplY3QgPC0gRmluZENsdXN0ZXJzKHNldXJhdC5vYmplY3QsIHJlc29sdXRpb24gPSB4KQp9CmBgYAoKYGBge3J9CmZvciAobWV0YS5jb2wgaW4gY29sbmFtZXMoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGEpKXsKCWlmKGdyZXBsKHBhdHRlcm4gPSAiUk5BX3Nubl9yZXMiLCB4ID0gbWV0YS5jb2wpPT1UUlVFIHwgZ3JlcGwocGF0dGVybiA9ICJvcmlnLmlkZW50IiwgeCA9IG1ldGEuY29sKT09VFJVRSl7CgkJbXlwbG90IDwtIERpbVBsb3Qoc2V1cmF0Lm9iamVjdCwgCgkJCQkJCQkJCQkJZ3JvdXAuYnkgPSBtZXRhLmNvbCwKCQkJCQkJCQkJCQlyZWR1Y3Rpb24gPSAidW1hcCIsIAoJCQkJCQkJCQkJCXB0LnNpemUgPSAxLAoJCQkJCQkJCQkJCWNvbHMgPSBjb2xvci5wYWxldHRlKSArIAoJCQlnZ3RpdGxlKHBhc3RlMChwcm9qZWN0TmFtZSwgIiBkaW0iLCBuZGltcywgInJlcy4iLCBnc3ViKCJSTkFfc25uX3Jlcy4iLCAiIiwgbWV0YS5jb2wpICkpCgkJcGxvdChteXBsb3QpCgkJcG5nKGZpbGVuYW1lID0gcGFzdGUwKHByb2plY3ROYW1lLCAiIGRpbSIsIG5kaW1zLCAicmVzLiIsIGdzdWIoIlJOQV9zbm5fcmVzLiIsICIiLCBtZXRhLmNvbCksICItdW1hcC5wbmciKSwgaGVpZ2h0ID0gODAwLCB3aWR0aCA9IDgwMCkKCQlwbG90KG15cGxvdCkKCQlkZXYub2ZmKCkKCQlteXBsb3QgPC0gRGltUGxvdChzZXVyYXQub2JqZWN0LCAKCQkJCQkJCQkJCQlncm91cC5ieSA9IG1ldGEuY29sLAoJCQkJCQkJCQkJCXJlZHVjdGlvbiA9ICJ1bWFwIiwgCgkJCQkJCQkJCQkJcHQuc2l6ZSA9IDEsCgkJCQkJCQkJCQkJY29scyA9IGNvbG9yLnBhbGV0dGUpICsgCgkJCWZhY2V0X3dyYXAobWV0YS5jb2wpICsgCgkJCWdndGl0bGUocGFzdGUwKHByb2plY3ROYW1lLCAiIGRpbSIsIG5kaW1zLCAicmVzLiIsIGdzdWIoIlJOQV9zbm5fcmVzLiIsICIiLCBtZXRhLmNvbCkpKQoJCQoJCXBuZyhmaWxlbmFtZSA9IHBhc3RlMChwcm9qZWN0TmFtZSwgIiBkaW0iLCBuZGltcywgInJlcy4iLCBnc3ViKCJSTkFfc25uX3Jlcy4iLCAiIiwgbWV0YS5jb2wpLCAiLXVtYXBfRmFjZXRSZXMucG5nIiksIGhlaWdodCA9IDgwMCwgd2lkdGggPSA4MDApCgkJcGxvdChteXBsb3QpCgkJZGV2Lm9mZigpCgkJCgl9Cn0KYGBgCgoKCmBgYHtyfQpzYXZlUkRTKHNldXJhdC5vYmplY3QsIGZpbGUgPSBwYXN0ZTAocHJvamVjdE5hbWUsICJfZGltIiwgbmRpbXMsICIuUkRTIikpCmBgYAoKR2VuZXJhdGUgc3RhdGlzdGljcyBmb3IgZWFjaCBjbHVzdGVyL3Jlc29sdXRpb24gY29tYm8KYGBge3J9CmN1cnJlbnRfcmVzIDwtICdSTkFfc25uX3Jlcy4xJwoKY2x1c3Rlcl9pZHMgPC0gc29ydCh1bmlxdWUoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbLGN1cnJlbnRfcmVzXSkpCmNvdW50c19kZiA8LSBkYXRhLmZyYW1lKG1hdHJpeChucm93ID0gbGVuZ3RoKGNsdXN0ZXJfaWRzKSwgbmNvbCA9IDkpKQpyb3duYW1lcyhjb3VudHNfZGYpIDwtIGNsdXN0ZXJfaWRzCmNvbG5hbWVzKGNvdW50c19kZikgPC0gYygiTFNLbTIiLCAiQ01QbTIiLCAiTUVQbSIsICJHTVBtIiwgIlRvdEluQ2x1c3QiLCAiUGN0Q2x1c0xTSyIsICJQY3RDbHVzQ01QIiwgIlBjdENsdXNNRVAiLCAiUGN0Q2x1c0dNUCIpCmZvcihpZCBpbiBjbHVzdGVyX2lkcyl7CgljZWxsX3ZhbHVlIDwtIG5yb3coc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhW2N1cnJlbnRfcmVzXSA9PSBpZCkgJiAKCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSAJKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhJG9yaWcuaWRlbnQgPT0gIkxTS20yIiksXSkKCWNvdW50c19kZltpZCwgIkxTS20yIl0gPSBjZWxsX3ZhbHVlCgljZWxsX3ZhbHVlIDwtIG5yb3coc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhW2N1cnJlbnRfcmVzXSA9PSBpZCkgJiAKCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSAJKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhJG9yaWcuaWRlbnQgPT0gIkNNUG0yIiksXSkKCWNvdW50c19kZltpZCwgIkNNUG0yIl0gPSBjZWxsX3ZhbHVlCgljZWxsX3ZhbHVlIDwtIG5yb3coc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhW2N1cnJlbnRfcmVzXSA9PSBpZCkgJiAKCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSAJKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhJG9yaWcuaWRlbnQgPT0gIk1FUG0iKSxdKQoJY291bnRzX2RmW2lkLCAiTUVQbSJdID0gY2VsbF92YWx1ZQoJY2VsbF92YWx1ZSA8LSBucm93KHNldXJhdC5vYmplY3RAbWV0YS5kYXRhWyhzZXVyYXQub2JqZWN0QG1ldGEuZGF0YVtjdXJyZW50X3Jlc10gPT0gaWQpICYgCgkJCQkJCQkJCQkJCQkJCQkJCQkJCQkgCShzZXVyYXQub2JqZWN0QG1ldGEuZGF0YSRvcmlnLmlkZW50ID09ICJHTVBtIiksXSkKCWNvdW50c19kZltpZCwgIkdNUG0iXSA9IGNlbGxfdmFsdWUKCQp9CmNvdW50c19kZlsiVG90SW5DbHVzdCJdIDwtIHJvd1N1bXMoY291bnRzX2RmLCBuYS5ybSA9IFRSVUUpCmNvdW50c19kZiRQY3RDbHVzTFNLIDwtIHJvdW5kKGNvdW50c19kZiRMU0ttMi9jb3VudHNfZGYkVG90SW5DbHVzdCwgMykqMTAwCmNvdW50c19kZiRQY3RDbHVzQ01QIDwtIHJvdW5kKGNvdW50c19kZiRDTVBtMi9jb3VudHNfZGYkVG90SW5DbHVzdCwgMykqMTAwCmNvdW50c19kZiRQY3RDbHVzTUVQIDwtIHJvdW5kKGNvdW50c19kZiRNRVBtL2NvdW50c19kZiRUb3RJbkNsdXN0LCAzKSoxMDAKY291bnRzX2RmJFBjdENsdXNHTVAgPC0gcm91bmQoY291bnRzX2RmJEdNUG0vY291bnRzX2RmJFRvdEluQ2x1c3QsIDMpKjEwMAp4bHN4Ojp3cml0ZS54bHN4KHggPSBjb3VudHNfZGYsIAoJCQkJCQkJCSBmaWxlID0gcGFzdGUwKHByb2plY3ROYW1lLCAiQ2VsbENvdW50UGVyQ2x1c3QiLG5kaW1zLCAicmVzLjEueGxzeCIpLCAKCQkJCQkJCQkgc2hlZXROYW1lID0gInJlczEiLCAKCQkJCQkJCQkgY29sLm5hbWVzID0gVFJVRSwgCgkJCQkJCQkJIHJvdy5uYW1lcyA9IFRSVUUsIAoJCQkJCQkJCSBhcHBlbmQgPSBUUlVFKQoKCmNvdW50c19kZgoKYGBgCgoKIyMjIEV2YWx1YXRlIGNsdXN0ZXIgc3RhYmlsaXR5CmBgYHtyIGZpZy5oZWlnaHQ9NX0KY2x1c3RyZWUoc2V1cmF0Lm9iamVjdCwgcHJlZml4ID0gIlJOQV9zbm5fcmVzLiIsIG5vZGVfY29sb3VyID0gInNjM19zdGFiaWxpdHkiKSArIAoJc2NhbGVfY29sb3JfY29udGludW91cyhsb3cgPSAncmVkMycsIGhpZ2ggPSAnd2hpdGUnKQpwbmcoZmlsZW5hbWUgPSBwYXN0ZTAocHJvamVjdE5hbWUsICJfZGltIiwgbmRpbXMsICItY2x1c3RyZWUucG5nIiksIGhlaWdodCA9IDgwMCwgd2lkdGggPSAxNjAwKQpjbHVzdHJlZShzZXVyYXQub2JqZWN0LCBwcmVmaXggPSAiUk5BX3Nubl9yZXMuIiwgbm9kZV9jb2xvdXIgPSAic2MzX3N0YWJpbGl0eSIpICsgCglzY2FsZV9jb2xvcl9jb250aW51b3VzKGxvdyA9ICdyZWQzJywgaGlnaCA9ICd3aGl0ZScpCmRldi5vZmYoKQpgYGAKYGBge3IgZmlnLmhlaWdodD01fQpjbHVzdHJlZShzZXVyYXQub2JqZWN0LCBwcmVmaXggPSAiUk5BX3Nubl9yZXMuIiwgZXhwcmVzID0gJ2RhdGEnLCBub2RlX2NvbG91ciA9ICJzYzNfc3RhYmlsaXR5IikgKyAKCXNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93ID0gJ3JlZDMnLCBoaWdoID0gJ3doaXRlJykKYGBgCmBgYHtyIGZpZy5oZWlnaHQ9NX0KY2x1c3RyZWUoc2V1cmF0Lm9iamVjdCwgcHJlZml4ID0gIlJOQV9zbm5fcmVzLiIsIGV4cHJlcyA9ICdzY2FsZS5kYXRhJywgbm9kZV9jb2xvdXIgPSAic2MzX3N0YWJpbGl0eSIpICsgCglzY2FsZV9jb2xvcl9jb250aW51b3VzKGxvdyA9ICdyZWQzJywgaGlnaCA9ICd3aGl0ZScpCmBgYApgYGB7ciBmaWcuaGVpZ2h0PTV9CmNsdXN0cmVlKHNldXJhdC5vYmplY3QsIHByZWZpeCA9ICJSTkFfc25uX3Jlcy4iLCBleHByZXMgPSAnY291bnRzJywgbm9kZV9jb2xvdXIgPSAic2MzX3N0YWJpbGl0eSIpICsgCglzY2FsZV9jb2xvcl9jb250aW51b3VzKGxvdyA9ICdyZWQzJywgaGlnaCA9ICd3aGl0ZScpCmBgYAojIyBEZXNjcmliZSA5NSUgb2YgdmFyaWFuY2Ugd2l0aCAzNyBkaW1lbnNpb25zCgojIyMgTmVpZ2hib3Job29kIGFuZCB1bWFwCmBgYHtyfQp0b3QudmFyIDwtIHBlcmNlbnQudmFyaWFuY2Uoc2V1cmF0Lm9iamVjdEByZWR1Y3Rpb25zJHBjYUBzdGRldiwgcGxvdC52YXIgPSBGQUxTRSwgcmV0dXJuLnZhbCA9IFRSVUUpCm5kaW1zIDwtIGxlbmd0aCh3aGljaChjdW1zdW0odG90LnZhcikgPD0gOTUpKQoKc2V1cmF0Lm9iamVjdCA8LSBGaW5kTmVpZ2hib3JzKHNldXJhdC5vYmplY3QsIGRpbXMgPSAxOm5kaW1zKQpzZXVyYXQub2JqZWN0IDwtIEZpbmRDbHVzdGVycyhzZXVyYXQub2JqZWN0LCByZXNvbHV0aW9uID0gMC41KQpzZXVyYXQub2JqZWN0IDwtIFJ1blVNQVAoc2V1cmF0Lm9iamVjdCwgZGltcyA9IDE6IG5kaW1zKQoKYGBgClBsb3QgVU1BUAoKYGBge3J9CmZvcih4IGluIGMoMC41LCAxLCAxLjUsIDIsIDIuNSkpewoJc2V1cmF0Lm9iamVjdCA8LSBGaW5kQ2x1c3RlcnMoc2V1cmF0Lm9iamVjdCwgcmVzb2x1dGlvbiA9IHgpCn0KYGBgCgpgYGB7cn0KZm9yIChtZXRhLmNvbCBpbiBjb2xuYW1lcyhzZXVyYXQub2JqZWN0QG1ldGEuZGF0YSkpewoJaWYoZ3JlcGwocGF0dGVybiA9ICgiUk5BX3Nubl9yZXMiKSwgeCA9IG1ldGEuY29sKT09VFJVRSl7CgkJbXlwbG90IDwtIERpbVBsb3Qoc2V1cmF0Lm9iamVjdCwgCgkJCQkJCQkJCQkJZ3JvdXAuYnkgPSBtZXRhLmNvbCwKCQkJCQkJCQkJCQlyZWR1Y3Rpb24gPSAidW1hcCIsIAoJCQkJCQkJCQkJCWNvbHMgPSBjb2xvci5wYWxldHRlCgkJKSArIAoJCQlnZ3RpdGxlKHBhc3RlMChwcm9qZWN0TmFtZSwgIiBkaW0iLCBuZGltcywgInJlcyIsIGdzdWIoIlJOQV9zbm5fcmVzIiwgIiIsIG1ldGEuY29sKSApKQoJCXBsb3QobXlwbG90KQoJfQp9CmBgYAoKYGBge3J9CnNhdmVSRFMoc2V1cmF0Lm9iamVjdCwgZmlsZSA9IHBhc3RlMChwcm9qZWN0TmFtZSwgIl9kaW0iLCBuZGltcywgIi5SRFMiKSkKYGBgCgpHZW5lcmF0ZSBzdGF0aXN0aWNzIGZvciBlYWNoIGNsdXN0ZXIvcmVzb2x1dGlvbiBjb21ibwpgYGB7cn0KY3VycmVudF9yZXMgPC0gJ1JOQV9zbm5fcmVzLjAuNScKCmNsdXN0ZXJfaWRzIDwtIHNvcnQodW5pcXVlKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhWyxjdXJyZW50X3Jlc10pKQpjb3VudHNfZGYgPC0gZGF0YS5mcmFtZShtYXRyaXgobnJvdyA9IGxlbmd0aChjbHVzdGVyX2lkcyksIG5jb2wgPSA0KSkKcm93bmFtZXMoY291bnRzX2RmKSA8LSBjbHVzdGVyX2lkcwpjb2xuYW1lcyhjb3VudHNfZGYpIDwtIGMoIkxTS20yIiwgIkNNUG0yIiwgIk1FUG0iLCAiR01QbSIpCmZvcihpZCBpbiBjbHVzdGVyX2lkcyl7CgljZWxsX3ZhbHVlIDwtIG5yb3coc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhW2N1cnJlbnRfcmVzXSA9PSBpZCkgJiAKCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSAJKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhJG9yaWcuaWRlbnQgPT0gIkxTS20yIiksXSkKCWNvdW50c19kZltpZCwgIkxTS20yIl0gPSBjZWxsX3ZhbHVlCgljZWxsX3ZhbHVlIDwtIG5yb3coc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhW2N1cnJlbnRfcmVzXSA9PSBpZCkgJiAKCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSAJKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhJG9yaWcuaWRlbnQgPT0gIkxTS20yIiksXSkKCWNvdW50c19kZltpZCwgIkNNUG0yIl0gPSBjZWxsX3ZhbHVlCgljZWxsX3ZhbHVlIDwtIG5yb3coc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhW2N1cnJlbnRfcmVzXSA9PSBpZCkgJiAKCQkJCQkJCQkJCQkJCQkJCQkJCQkJCSAJKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhJG9yaWcuaWRlbnQgPT0gIk1FUG0iKSxdKQoJY291bnRzX2RmW2lkLCAiTUVQbSJdID0gY2VsbF92YWx1ZQoJY2VsbF92YWx1ZSA8LSBucm93KHNldXJhdC5vYmplY3RAbWV0YS5kYXRhWyhzZXVyYXQub2JqZWN0QG1ldGEuZGF0YVtjdXJyZW50X3Jlc10gPT0gaWQpICYgCgkJCQkJCQkJCQkJCQkJCQkJCQkJCQkgCShzZXVyYXQub2JqZWN0QG1ldGEuZGF0YSRvcmlnLmlkZW50ID09ICJHTVBtIiksXSkKCWNvdW50c19kZltpZCwgIkdNUG0iXSA9IGNlbGxfdmFsdWUKCQp9CgpgYGAKCgojIyMgRXZhbHVhdGUgY2x1c3RlciBzdGFiaWxpdHkKYGBge3IgZmlnLmhlaWdodD01fQpjbHVzdHJlZShzZXVyYXQub2JqZWN0LCBwcmVmaXggPSAiUk5BX3Nubl9yZXMuIiwgbm9kZV9jb2xvdXIgPSAic2MzX3N0YWJpbGl0eSIpICsgCglzY2FsZV9jb2xvcl9jb250aW51b3VzKGxvdyA9ICdyZWQzJywgaGlnaCA9ICd3aGl0ZScpCmBgYAoKCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmNsdXN0cmVlKHNldXJhdC5vYmplY3QsIHByZWZpeCA9ICJSTkFfc25uX3Jlcy4iLCBleHByZXMgPSAnZGF0YScsIG5vZGVfY29sb3VyID0gInNjM19zdGFiaWxpdHkiKSArIAoJc2NhbGVfY29sb3JfY29udGludW91cyhsb3cgPSAncmVkMycsIGhpZ2ggPSAnd2hpdGUnKQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmNsdXN0cmVlKHNldXJhdC5vYmplY3QsIHByZWZpeCA9ICJSTkFfc25uX3Jlcy4iLCBleHByZXMgPSAnc2NhbGUuZGF0YScsIG5vZGVfY29sb3VyID0gInNjM19zdGFiaWxpdHkiKSArIAoJc2NhbGVfY29sb3JfY29udGludW91cyhsb3cgPSAncmVkMycsIGhpZ2ggPSAnd2hpdGUnKQpgYGAKCgoKYGBge3IgZmlnLmhlaWdodD01fQpjbHVzdHJlZShzZXVyYXQub2JqZWN0LCBwcmVmaXggPSAiUk5BX3Nubl9yZXMuIiwgZXhwcmVzID0gJ2NvdW50cycsIG5vZGVfY29sb3VyID0gInNjM19zdGFiaWxpdHkiKSArIAoJc2NhbGVfY29sb3JfY29udGludW91cyhsb3cgPSAncmVkMycsIGhpZ2ggPSAnd2hpdGUnKQpgYGAKCgoKCgoKCgoKCgoKCgojIERHRQpJIHRoaW5rIGNsdXN0ZXJzIGZyb20gOTAlIHZhcmlhbmNlIGF0IDAuNSBhbmQgMS4wIHJlc29sdXRpb24gYXJlIG1vc3Qgc3RhYmxlLiBXZSdsbCBkbyBzb21lIHN0YXRpc3RpY3MgYW5kIERHRSBvbiB0aGF0LiBXaWxsIGFsc28gbmVlZCB0byBnbyBiYWNrIGFuZCBwbGF5IHdpdGggU0NUcmFuc2Zvcm0sIHNpbmNlIHRoZXNlIGFyZSBtdWx0aXBsZSBjZWxsIHR5cGVzIGZyb20gbXVsdGlwbGUgbGFuZXMuCiMjIExvYWQgZmF2b3VyaXRlIGRpbSByZWR1Y3Rpb24gZmlsZQpgYGB7cn0KcmRzLmZpbGUgPC0gIm1zQWdncl9zZXVyYXRfZGltMjYuUkRTIgpzZXVyYXQub2JqZWN0IDwtIHJlYWRSRFMocmRzLmZpbGUpCm5kaW1zIDwtIGFzLm51bWVyaWMoZ3N1YigiW14wLTldIiwgIiIsIHN0cmluZ3I6OnN0cl9zcGxpdChyZHMuZmlsZSwgIl8iKVtbMV1dWzNdKSkKYGBgCgojIyBTZXQgZmF2b3VyaXRlIHJlc29sdXRpb24KYGBge3J9Cm9iamVjdC5yZXMgPC0gIi4wLjUiCklkZW50cyhzZXVyYXQub2JqZWN0KSA8LSBwYXN0ZTAoIlJOQV9zbm5fcmVzIiwgb2JqZWN0LnJlcykKbGVuZ3RoKGxldmVscyhzZXVyYXQub2JqZWN0QGFjdGl2ZS5pZGVudCkpCmBgYAoKCiMjIGNvdW50IG51bWJlciBvZiBmaWx0ZXJlZCBjZWxscyBsZWZ0IGZyb20gZWFjaCBwb3B1bGF0aW9uCmBgYHtyfQojIE51bWJlciBvZiBmaWx0ZXJlZCBjZWxscyBsZWZ0IGluIGVhY2ggcG9wCnNhcHBseShjKCJMU0ttMiIsICJDTVBtMiIsICJNRVBtIiwgIkdNUG0iKSwgZnVuY3Rpb24oeCkgKGMobnJvdyhzZXVyYXQub2JqZWN0QG1ldGEuZGF0YVtzZXVyYXQub2JqZWN0QG1ldGEuZGF0YSRvcmlnLmlkZW50ID09IHgsXSkpKSkKYGBgCgpgYGB7cn0KcGFyKG1mcm93ID0gYygyLCAyKSkKZm9yICh4IGluIGMoIkxTS20yIiwgIkNNUG0yIiwgIk1FUG0iLCAiR01QbSIpKXsKCWggPSBoaXN0KHNldXJhdC5vYmplY3RAbWV0YS5kYXRhW3NldXJhdC5vYmplY3RAbWV0YS5kYXRhJG9yaWcuaWRlbnQgPT0geCwgJ3BlcmNlbnQubXQnXSwgYnJlYWtzID0gMzAsIHBsb3QgPSBGQUxTRSkKCWgkZGVuc2l0eSA9IGgkY291bnRzL3N1bShoJGNvdW50cykqMTAwCglwbG90KGgsZnJlcT1GQUxTRSwgbWFpbiA9ICBwYXN0ZSh4LCAicGVyY2VudCBtaXRvQyIpLCB4bGFiID0gInBlcmNlbnQgbWl0b0MiLCB5bGFiID0gIkZyZXF1ZW5jeSIpCn0KcGFyKG1mcm93ID0gYygxLDEpKQpgYGAKCmBgYHtyIGZpZy53aWR0aD01fQpWbG5QbG90KHN1YnNldChzZXVyYXQub2JqZWN0LCBzdWJzZXQgPSBvcmlnLmlkZW50ID09ICJNRVBtIiksIAoJCQkJZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiLCAibkNvdW50X1JOQSIsICJwZXJjZW50Lm10IiksIG5jb2wgPSAxLCBwdC5zaXplID0gMCwgZmlsbC5ieSA9ICdpZGVudCcsIGZsaXAgPSBUUlVFKQpgYGAKCgojIyBER0Ugdy8gcmVzb2x1dGlvbiA9IDAuNQpTdHJ0IHdpdGggY29tcGFyaW5nIGFsbCBjbHVzdGVycyBhZ2FpbnN0IGFsbCBvdGhlciBjbHVzdGVycyBhbmQgd3JpdGUgb3V0IGNsdXN0ZXIgaW5mbwpjYWxjdWxhdGUgYEZpbmRBbGxNYXJrZXJzKClgIGZvciBkaWZmZXJlbnQgaWRlbnRzIGFuZCBzYXZlIHRvIG5ldyBmaWxlCmBgYHtyfQojIGlkZW50Lmxpc3QgPC0gY29sbmFtZXMoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGEpW2dyZXBsKCJeUk5BX3NubiIsIGNvbG5hbWVzKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhKSldCmlkZW50Lmxpc3QgPC0gYygiUk5BX3Nubl9yZXMuMC41IiwgIlJOQV9zbm5fcmVzLjEiKQoKZm9yKHRlc3RlZC5pZGVudCBpbiBpZGVudC5saXN0KXsKCUlkZW50cyhzZXVyYXQub2JqZWN0KSA8LSB0ZXN0ZWQuaWRlbnQKCWFsbC5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKHNldXJhdC5vYmplY3QpCgl4bHN4Ojp3cml0ZS54bHN4KHggPSBhbGwubWFya2Vyc1ssYygiYXZnX2xvZzJGQyIsICJwX3ZhbF9hZGoiLCAiY2x1c3RlciIsICJnZW5lIildLCAKCQkJCQkJCQkJIGZpbGUgPSBwYXN0ZTAocHJvamVjdE5hbWUsICJfRmluZEFMTE1hcmtlcnNfZGltIixuZGltcywgIl9hbGxyZXMueGxzeCIpLCAKCQkJCQkJCQkJIHNoZWV0TmFtZSA9IHRlc3RlZC5pZGVudCwgCgkJCQkJCQkJCSBjb2wubmFtZXMgPSBUUlVFLCAKCQkJCQkJCQkJIHJvdy5uYW1lcyA9IEZBTFNFLCAKCQkJCQkJCQkJIGFwcGVuZCA9IFRSVUUpCn0KYGBgCgojIyBDcmVhdGUgYEZpbmRBbGxNYXJrZXJzKClgIGxpc3RzIGZvciBHU0VBCmBgYHtyfQpvYmplY3QucmVzLmFsbG1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoc2V1cmF0Lm9iamVjdCkKYGBgCgojIyBNYXAgSEdOQyBzeW1ib2xzCmBgYHtyfQpNb3VzZTJIdW1hblRhYmxlIDwtIE1vdXNlMkh1bWFuKG9iamVjdC5yZXMuYWxsbWFya2VycyRnZW5lKQoKSEdOQyA8LSB3aXRoKE1vdXNlMkh1bWFuVGFibGUsIE1vdXNlMkh1bWFuVGFibGUkSEdOQ1ttYXRjaChvYmplY3QucmVzLmFsbG1hcmtlcnMkZ2VuZSwgTW91c2UySHVtYW5UYWJsZSRNR0kpXSkKaGVhZChvYmplY3QucmVzLmFsbG1hcmtlcnMpCm9iamVjdC5yZXMuYWxsbWFya2VycyRIR05DIDwtIEhHTkMKdGFpbChvYmplY3QucmVzLmFsbG1hcmtlcnMpCnNpZy5yZXMgPC0gb2JqZWN0LnJlcy5hbGxtYXJrZXJzW29iamVjdC5yZXMuYWxsbWFya2VycyRwX3ZhbF9hZGogPD0gMC4wNSwgXQpzaWcucmVzIDwtIHNpZy5yZXNbYygiYXZnX2xvZzJGQyIsICJIR05DIiwgImNsdXN0ZXIiKV0Kc2lnLnJlcyA8LSBzaWcucmVzWyEoc2lnLnJlcyRIR05DID09ICIiIHwgaXMubmEoc2lnLnJlcyRIR05DKSksXSAjIEdTRUEgd2lsbCBmYWlsIGlmIHRoZXJlIGFyZSBhbnkgYmxhbmtzIG9yIE5BcyBpbiB0aGUgdGFibGUKc2lnLnJlcyA8LSBzaWcucmVzW10KCmBgYAoKCmBgYHtyfQpmb3IoY2x1c3RlciBpbiB1bmlxdWUoc2lnLnJlcyRjbHVzdGVyKSl7CglwcmludChwYXN0ZSgid3JpdGluZyBjbHVzdGVyIiwgY2x1c3RlcikpCgluZXcudGFibGUgPC0gc2lnLnJlc1tzaWcucmVzJGNsdXN0ZXIgPT0gY2x1c3RlciwgYygiSEdOQyIsICJhdmdfbG9nMkZDIildCgluZXcudGFibGUgPC0gbmV3LnRhYmxlW29yZGVyKC1uZXcudGFibGUkYXZnX2xvZzJGQyksIF0KCWRpci5jcmVhdGUocGFzdGUwKCJSYW5rTGlzdF9yZXMiLCBvYmplY3QucmVzLCAiX2ZpbmRBbGxfaGduYy8iKSwgc2hvd1dhcm5pbmdzID0gRkFMU0UpCgl3cml0ZS50YWJsZShuZXcudGFibGUsIGZpbGUgPSBwYXN0ZTAoIlJhbmtMaXN0X3JlcyIsIG9iamVjdC5yZXMsICJfZmluZEFsbF9oZ25jL3JlcyIsIG9iamVjdC5yZXMsICJjbHVzdGVyIiwgY2x1c3RlciwgIi5ybmsiKSwgcXVvdGUgPSBGQUxTRSwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUsIHNlcCA9ICJcdCIsICkKCQp9CmBgYAoKCgpjYWxjdWxhdGUgYEZpbmRNYXJrZXJzKClgIHRoYXQgZGlzdGluZ3Vpc2ggZWFjaCBjbHVzdGVyIChtaWdodCBvdmVybGFiIGJldHdlZW4gY2x1c3RlcnMpCmBgYHtyfQojIGlkZW50Lmxpc3QgPC0gY29sbmFtZXMoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGEpW2dyZXBsKCJeUk5BX3NubiIsIGNvbG5hbWVzKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhKSldCmlkZW50Lmxpc3QgPC0gYygiUk5BX3Nubl9yZXMuMC41IiwgIlJOQV9zbm5fcmVzLjEiKQpmb3IodGVzdGVkLmlkZW50IGluIGlkZW50Lmxpc3QpewoJZm9yIChjbHVzdGVyIGluIHNvcnQoYXMubnVtZXJpYyhsZXZlbHMoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbW3Rlc3RlZC5pZGVudF1dKSkpKXsKCQljbHVzdGVyLm1hcmtlcnMgPC0gRmluZE1hcmtlcnMoc2V1cmF0Lm9iamVjdCwgaWRlbnQuMSA9IGNsdXN0ZXIpCgkJeGxzeDo6d3JpdGUueGxzeCh4ID0gY2x1c3Rlci5tYXJrZXJzWyxjKCJhdmdfbG9nMkZDIiwgInBfdmFsX2FkaiIpXSwgCgkJCQkJCQkJCQkgZmlsZSA9IHBhc3RlMChwcm9qZWN0TmFtZSwgIl9GaW5kTWFya2Vyc19kaW0iLCBuZGltcywgZ3N1YigiUk5BX3Nubl8iLCAiIiwgdGVzdGVkLmlkZW50KSwgIi54bHN4IiksIAoJCQkJCQkJCQkJIHNoZWV0TmFtZSA9IHBhc3RlMCgiY2xzdCIsIGNsdXN0ZXIpLCAKCQkJCQkJCQkJCSBjb2wubmFtZXMgPSBUUlVFLCAKCQkJCQkJCQkJCSByb3cubmFtZXMgPSBUUlVFLCAKCQkJCQkJCQkJCSBhcHBlbmQgPSBUUlVFKQoJfQp9CmBgYAoKCgpgYGB7cn0KZm9yIChjbHVzdGVyIGluIHNvcnQoYXMubnVtZXJpYyhsZXZlbHMoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGFbcGFzdGUwKCJSTkFfc25uX3JlcyIsIG9iamVjdC5yZXMpXSkpKSl7CgljbHVzdGVyLm1hcmtlcnMgPC0gRmluZE1hcmtlcnMoc2V1cmF0Lm9iamVjdCwgaWRlbnQuMSA9IGNsdXN0ZXIpCgl4bHN4Ojp3cml0ZS54bHN4KHggPSBjbHVzdGVyLm1hcmtlcnNbLGMoImF2Z19sb2cyRkMiLCAicF92YWxfYWRqIildLCAKCQkJCQkJCQkJIGZpbGUgPSBwYXN0ZTAocHJvamVjdE5hbWUsICJfRmluZE1hcmtlcnNfZGltIiwgbmRpbXMsICJyZXMiLCBvYmplY3QucmVzLCAiLnhsc3giKSwgCgkJCQkJCQkJCSBzaGVldE5hbWUgPSBwYXN0ZTAoImNsc3QiLCBjbHVzdGVyKSwgCgkJCQkJCQkJCSBjb2wubmFtZXMgPSBUUlVFLCAKCQkJCQkJCQkJIHJvdy5uYW1lcyA9IFRSVUUsIAoJCQkJCQkJCQkgYXBwZW5kID0gVFJVRSkKfQpgYGAKCgojIE5vdGVzIG9uIGNsdXN0ZXIgc3RhYmlsaXR5CkNsdXN0ZXIgc3RhYmlsaXR5IGNvdWxkIGJlIGluZmx1ZW5jZWQgYnk6CiogY2VsbHMgaW4gZWFjaCBwb3B1bGF0aW9uIChjZWxscmFuZ2VyIHY2IGluY2x1ZGVzIG1vcmUgY2VsbHMgdGhhbiBjZWxscmFuZ2VyIHYxLCBlc3BlY2lhbGx5IGluIE1FUCkKKiBkaW1lbnNpb25hbGl0eSBpcyBpbmNvcnJlY3QKKiBTY2FsZURhdGEgZGlkbnQgYWNjb3VudCBmb3IgcmVncmVzc2lvbiBmYWN0b3JzIChlLmcuLCAibkNvdW50c19STkEiIG9yICJuRmVhdHVyZXNfUk5BIikKKiBEaWQgbm90IGNvbnNpZGVyIGNlbGwgY3ljbGUKKiBJbmNvcnJlY3Qgbm9ybWFsaXphdGlvbi9zY2FsaW5nIG1ldGhvZAoqIENsdXN0ZXJpbmcgaXMgdG9vIHN0cmljdCBvciBub3Qgc3RyaWN0IGVub3VnaAoqIG5laWdoYm9yaG9vZCBhbmFseXNpcyB1c2VkIHdyb25nIHBhcmFtZXRlcnMKKiBTaG91bGQgaW5jbHVkZSBtaXRvQyBmaWx0ZXIgKHRoZXJlJ3MgYSBjaHVuayBvZiBNRVAgdy8gbWl0b0MgQCB+NDAlKQoqIFNDVHJhbnNmb3JtIGFjY291bnRzIGJldHRlciBmb3Igc291cmNlcyBvZiB2YXJpYWJpbGl0eQo=